• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2023 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.internal.telephony.satellite;
18 
19 import android.annotation.ArrayRes;
20 import android.annotation.NonNull;
21 import android.annotation.Nullable;
22 import android.bluetooth.BluetoothAdapter;
23 import android.content.BroadcastReceiver;
24 import android.content.ContentResolver;
25 import android.content.Context;
26 import android.content.Intent;
27 import android.content.IntentFilter;
28 import android.content.SharedPreferences;
29 import android.content.res.Resources;
30 import android.database.ContentObserver;
31 import android.net.wifi.WifiManager;
32 import android.nfc.NfcAdapter;
33 import android.os.AsyncResult;
34 import android.os.Binder;
35 import android.os.Build;
36 import android.os.Bundle;
37 import android.os.CancellationSignal;
38 import android.os.Handler;
39 import android.os.HandlerExecutor;
40 import android.os.HandlerThread;
41 import android.os.IBinder;
42 import android.os.ICancellationSignal;
43 import android.os.Looper;
44 import android.os.Message;
45 import android.os.PersistableBundle;
46 import android.os.RemoteException;
47 import android.os.ResultReceiver;
48 import android.os.SystemProperties;
49 import android.provider.Settings;
50 import android.telephony.CarrierConfigManager;
51 import android.telephony.Rlog;
52 import android.telephony.SubscriptionManager;
53 import android.telephony.TelephonyManager;
54 import android.telephony.satellite.ISatelliteDatagramCallback;
55 import android.telephony.satellite.ISatelliteProvisionStateCallback;
56 import android.telephony.satellite.ISatelliteStateCallback;
57 import android.telephony.satellite.ISatelliteTransmissionUpdateCallback;
58 import android.telephony.satellite.SatelliteCapabilities;
59 import android.telephony.satellite.SatelliteDatagram;
60 import android.telephony.satellite.SatelliteManager;
61 import android.util.Log;
62 import android.util.SparseArray;
63 import android.uwb.UwbManager;
64 
65 import com.android.internal.R;
66 import com.android.internal.annotations.GuardedBy;
67 import com.android.internal.annotations.VisibleForTesting;
68 import com.android.internal.telephony.CommandsInterface;
69 import com.android.internal.telephony.IIntegerConsumer;
70 import com.android.internal.telephony.Phone;
71 import com.android.internal.telephony.satellite.metrics.ControllerMetricsStats;
72 import com.android.internal.telephony.satellite.metrics.ProvisionMetricsStats;
73 import com.android.internal.telephony.satellite.metrics.SessionMetricsStats;
74 import com.android.internal.telephony.subscription.SubscriptionManagerService;
75 import com.android.internal.util.FunctionalUtils;
76 
77 import java.util.ArrayList;
78 import java.util.HashMap;
79 import java.util.List;
80 import java.util.Map;
81 import java.util.Set;
82 import java.util.concurrent.ConcurrentHashMap;
83 import java.util.concurrent.atomic.AtomicBoolean;
84 import java.util.function.Consumer;
85 
86 /**
87  * Satellite controller is the backend service of
88  * {@link android.telephony.satellite.SatelliteManager}.
89  */
90 public class SatelliteController extends Handler {
91     private static final String TAG = "SatelliteController";
92     /** Whether enabling verbose debugging message or not. */
93     private static final boolean DBG = false;
94     private static final String ALLOW_MOCK_MODEM_PROPERTY = "persist.radio.allow_mock_modem";
95     private static final boolean DEBUG = !"user".equals(Build.TYPE);
96     /** File used to store shared preferences related to satellite. */
97     public static final String SATELLITE_SHARED_PREF = "satellite_shared_pref";
98     /** Value to pass for the setting key SATELLITE_MODE_ENABLED, enabled = 1, disabled = 0 */
99     public static final int SATELLITE_MODE_ENABLED_TRUE = 1;
100     public static final int SATELLITE_MODE_ENABLED_FALSE = 0;
101 
102     /** Message codes used in handleMessage() */
103     //TODO: Move the Commands and events related to position updates to PointingAppController
104     private static final int CMD_START_SATELLITE_TRANSMISSION_UPDATES = 1;
105     private static final int EVENT_START_SATELLITE_TRANSMISSION_UPDATES_DONE = 2;
106     private static final int CMD_STOP_SATELLITE_TRANSMISSION_UPDATES = 3;
107     private static final int EVENT_STOP_SATELLITE_TRANSMISSION_UPDATES_DONE = 4;
108     private static final int CMD_PROVISION_SATELLITE_SERVICE = 7;
109     private static final int EVENT_PROVISION_SATELLITE_SERVICE_DONE = 8;
110     private static final int CMD_DEPROVISION_SATELLITE_SERVICE = 9;
111     private static final int EVENT_DEPROVISION_SATELLITE_SERVICE_DONE = 10;
112     private static final int CMD_SET_SATELLITE_ENABLED = 11;
113     private static final int EVENT_SET_SATELLITE_ENABLED_DONE = 12;
114     private static final int CMD_IS_SATELLITE_ENABLED = 13;
115     private static final int EVENT_IS_SATELLITE_ENABLED_DONE = 14;
116     private static final int CMD_IS_SATELLITE_SUPPORTED = 15;
117     private static final int EVENT_IS_SATELLITE_SUPPORTED_DONE = 16;
118     private static final int CMD_GET_SATELLITE_CAPABILITIES = 17;
119     private static final int EVENT_GET_SATELLITE_CAPABILITIES_DONE = 18;
120     private static final int CMD_IS_SATELLITE_COMMUNICATION_ALLOWED = 19;
121     private static final int EVENT_IS_SATELLITE_COMMUNICATION_ALLOWED_DONE = 20;
122     private static final int CMD_GET_TIME_SATELLITE_NEXT_VISIBLE = 21;
123     private static final int EVENT_GET_TIME_SATELLITE_NEXT_VISIBLE_DONE = 22;
124     private static final int EVENT_RADIO_STATE_CHANGED = 23;
125     private static final int CMD_IS_SATELLITE_PROVISIONED = 24;
126     private static final int EVENT_IS_SATELLITE_PROVISIONED_DONE = 25;
127     private static final int EVENT_SATELLITE_PROVISION_STATE_CHANGED = 26;
128     private static final int EVENT_PENDING_DATAGRAMS = 27;
129     private static final int EVENT_SATELLITE_MODEM_STATE_CHANGED = 28;
130 
131     @NonNull private static SatelliteController sInstance;
132     @NonNull private final Context mContext;
133     @NonNull private final SatelliteModemInterface mSatelliteModemInterface;
134     @NonNull private SatelliteSessionController mSatelliteSessionController;
135     @NonNull private final PointingAppController mPointingAppController;
136     @NonNull private final DatagramController mDatagramController;
137     @NonNull private final ControllerMetricsStats mControllerMetricsStats;
138     @NonNull private final ProvisionMetricsStats mProvisionMetricsStats;
139     private SharedPreferences mSharedPreferences = null;
140     private final CommandsInterface mCi;
141     private ContentResolver mContentResolver = null;
142 
143     private final Object mRadioStateLock = new Object();
144 
145     /** Flags to indicate whether the resepective radio is enabled */
146     @GuardedBy("mRadioStateLock")
147     private boolean mBTStateEnabled = false;
148     @GuardedBy("mRadioStateLock")
149     private boolean mNfcStateEnabled = false;
150     @GuardedBy("mRadioStateLock")
151     private boolean mUwbStateEnabled = false;
152     @GuardedBy("mRadioStateLock")
153     private boolean mWifiStateEnabled = false;
154 
155     // Flags to indicate that respective radios need to be disabled when satellite is enabled
156     private boolean mDisableBTOnSatelliteEnabled = false;
157     private boolean mDisableNFCOnSatelliteEnabled = false;
158     private boolean mDisableUWBOnSatelliteEnabled = false;
159     private boolean mDisableWifiOnSatelliteEnabled = false;
160 
161     private final Object mSatelliteEnabledRequestLock = new Object();
162     @GuardedBy("mSatelliteEnabledRequestLock")
163     private RequestSatelliteEnabledArgument mSatelliteEnabledRequest = null;
164     /** Flag to indicate that satellite is enabled successfully
165      * and waiting for all the radios to be disabled so that success can be sent to callback
166      */
167     @GuardedBy("mSatelliteEnabledRequestLock")
168     private boolean mWaitingForRadioDisabled = false;
169 
170     private boolean mWaitingForDisableSatelliteModemResponse = false;
171     private boolean mWaitingForSatelliteModemOff = false;
172 
173     private final AtomicBoolean mRegisteredForProvisionStateChangedWithSatelliteService =
174             new AtomicBoolean(false);
175     private final AtomicBoolean mRegisteredForProvisionStateChangedWithPhone =
176             new AtomicBoolean(false);
177     private final AtomicBoolean mRegisteredForPendingDatagramCountWithSatelliteService =
178             new AtomicBoolean(false);
179     private final AtomicBoolean mRegisteredForPendingDatagramCountWithPhone =
180             new AtomicBoolean(false);
181     private final AtomicBoolean mRegisteredForSatelliteModemStateChangedWithSatelliteService =
182             new AtomicBoolean(false);
183     private final AtomicBoolean mRegisteredForSatelliteModemStateChangedWithPhone =
184             new AtomicBoolean(false);
185     /**
186      * Map key: subId, value: callback to get error code of the provision request.
187      */
188     private final ConcurrentHashMap<Integer, Consumer<Integer>> mSatelliteProvisionCallbacks =
189             new ConcurrentHashMap<>();
190 
191     /**
192      * Map key: binder of the callback, value: callback to receive provision state changed events.
193      */
194     private final ConcurrentHashMap<IBinder, ISatelliteProvisionStateCallback>
195             mSatelliteProvisionStateChangedListeners = new ConcurrentHashMap<>();
196     private final Object mIsSatelliteSupportedLock = new Object();
197     @GuardedBy("mIsSatelliteSupportedLock")
198     private Boolean mIsSatelliteSupported = null;
199     private boolean mIsDemoModeEnabled = false;
200     private final Object mIsSatelliteEnabledLock = new Object();
201     @GuardedBy("mIsSatelliteEnabledLock")
202     private Boolean mIsSatelliteEnabled = null;
203     private boolean mIsRadioOn = false;
204     private final Object mIsSatelliteProvisionedLock = new Object();
205     @GuardedBy("mIsSatelliteProvisionedLock")
206     private Boolean mIsSatelliteProvisioned = null;
207     private final Object mSatelliteCapabilitiesLock = new Object();
208     @GuardedBy("mSatelliteCapabilitiesLock")
209     private SatelliteCapabilities mSatelliteCapabilities;
210     private final Object mNeedsSatellitePointingLock = new Object();
211     @GuardedBy("mNeedsSatellitePointingLock")
212     private boolean mNeedsSatellitePointing = false;
213     /** Key: subId, value: (key: PLMN, value: set of
214      * {@link android.telephony.NetworkRegistrationInfo.ServiceType})
215      */
216     @GuardedBy("mSupportedSatelliteServicesLock")
217     @NonNull private final Map<Integer, Map<String, Set<Integer>>> mSupportedSatelliteServices =
218             new HashMap<>();
219     @NonNull private final Object mSupportedSatelliteServicesLock = new Object();
220     /** Key: PLMN, value: set of {@link android.telephony.NetworkRegistrationInfo.ServiceType} */
221     @NonNull private final Map<String, Set<Integer>> mSatelliteServicesSupportedByProviders;
222     @NonNull private final CarrierConfigManager mCarrierConfigManager;
223     @NonNull private final CarrierConfigManager.CarrierConfigChangeListener
224             mCarrierConfigChangeListener;
225     @NonNull private final Object mCarrierConfigArrayLock = new Object();
226     @GuardedBy("mCarrierConfigArrayLock")
227     @NonNull private final SparseArray<PersistableBundle> mCarrierConfigArray = new SparseArray<>();
228     @NonNull private final List<String> mSatellitePlmnList;
229 
230     /**
231      * @return The singleton instance of SatelliteController.
232      */
getInstance()233     public static SatelliteController getInstance() {
234         if (sInstance == null) {
235             loge("SatelliteController was not yet initialized.");
236         }
237         return sInstance;
238     }
239 
240     /**
241      * Create the SatelliteController singleton instance.
242      * @param context The Context to use to create the SatelliteController.
243      */
make(@onNull Context context)244     public static void make(@NonNull Context context) {
245         if (sInstance == null) {
246             HandlerThread satelliteThread = new HandlerThread(TAG);
247             satelliteThread.start();
248             sInstance = new SatelliteController(context, satelliteThread.getLooper());
249         }
250     }
251 
252     /**
253      * Create a SatelliteController to act as a backend service of
254      * {@link android.telephony.satellite.SatelliteManager}
255      *
256      * @param context The Context for the SatelliteController.
257      * @param looper The looper for the handler. It does not run on main thread.
258      */
259     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
SatelliteController(@onNull Context context, @NonNull Looper looper)260     public SatelliteController(@NonNull Context context, @NonNull Looper looper) {
261         super(looper);
262 
263         mContext = context;
264         Phone phone = SatelliteServiceUtils.getPhone();
265         mCi = phone.mCi;
266         // Create the SatelliteModemInterface singleton, which is used to manage connections
267         // to the satellite service and HAL interface.
268         mSatelliteModemInterface = SatelliteModemInterface.make(mContext, this);
269 
270         // Create the PointingUIController singleton,
271         // which is used to manage interactions with PointingUI app.
272         mPointingAppController = PointingAppController.make(mContext);
273 
274         // Create the SatelliteControllerMetrics to report controller metrics
275         // should be called before making DatagramController
276         mControllerMetricsStats = ControllerMetricsStats.make(mContext);
277         mProvisionMetricsStats = ProvisionMetricsStats.getOrCreateInstance();
278 
279         // Create the DatagramController singleton,
280         // which is used to send and receive satellite datagrams.
281         mDatagramController = DatagramController.make(mContext, looper, mPointingAppController);
282 
283         requestIsSatelliteSupported(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID,
284                 new ResultReceiver(this) {
285                     @Override
286                     protected void onReceiveResult(int resultCode, Bundle resultData) {
287                         logd("requestIsSatelliteSupported: resultCode=" + resultCode);
288                     }
289                 });
290         mCi.registerForRadioStateChanged(this, EVENT_RADIO_STATE_CHANGED, null);
291         mIsRadioOn = phone.isRadioOn();
292         registerForSatelliteProvisionStateChanged();
293         registerForPendingDatagramCount();
294         registerForSatelliteModemStateChanged();
295         mContentResolver = mContext.getContentResolver();
296         mCarrierConfigManager = mContext.getSystemService(CarrierConfigManager.class);
297 
298         try {
299             mSharedPreferences = mContext.getSharedPreferences(SATELLITE_SHARED_PREF,
300                     Context.MODE_PRIVATE);
301         } catch (Exception e) {
302             loge("Cannot get default shared preferences: " + e);
303         }
304 
305         initializeSatelliteModeRadios();
306 
307         ContentObserver satelliteModeRadiosContentObserver = new ContentObserver(this) {
308             @Override
309             public void onChange(boolean selfChange) {
310                 initializeSatelliteModeRadios();
311             }
312         };
313         if (mContentResolver != null) {
314             mContentResolver.registerContentObserver(
315                     Settings.Global.getUriFor(Settings.Global.SATELLITE_MODE_RADIOS),
316                     false, satelliteModeRadiosContentObserver);
317         }
318 
319         mSatelliteServicesSupportedByProviders = readSupportedSatelliteServicesFromOverlayConfig();
320         mSatellitePlmnList =
321                 mSatelliteServicesSupportedByProviders.keySet().stream().toList();
322         updateSupportedSatelliteServicesForActiveSubscriptions();
323         mCarrierConfigChangeListener =
324                 (slotIndex, subId, carrierId, specificCarrierId) ->
325                         handleCarrierConfigChanged(slotIndex, subId, carrierId, specificCarrierId);
326         mCarrierConfigManager.registerCarrierConfigChangeListener(
327                         new HandlerExecutor(new Handler(looper)), mCarrierConfigChangeListener);
328     }
329 
330     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
initializeSatelliteModeRadios()331     protected void initializeSatelliteModeRadios() {
332         if (mContentResolver != null) {
333             BTWifiNFCStateReceiver bTWifiNFCSateReceiver = new BTWifiNFCStateReceiver();
334             UwbAdapterStateCallback uwbAdapterStateCallback = new UwbAdapterStateCallback();
335             IntentFilter radioStateIntentFilter = new IntentFilter();
336 
337             synchronized (mRadioStateLock) {
338                 // Initialize radio states to default value
339                 mDisableBTOnSatelliteEnabled = false;
340                 mDisableNFCOnSatelliteEnabled = false;
341                 mDisableWifiOnSatelliteEnabled = false;
342                 mDisableUWBOnSatelliteEnabled = false;
343 
344                 mBTStateEnabled = false;
345                 mNfcStateEnabled = false;
346                 mWifiStateEnabled = false;
347                 mUwbStateEnabled = false;
348 
349                 // Read satellite mode radios from settings
350                 String satelliteModeRadios = Settings.Global.getString(mContentResolver,
351                         Settings.Global.SATELLITE_MODE_RADIOS);
352                 if (satelliteModeRadios == null) {
353                     loge("initializeSatelliteModeRadios: satelliteModeRadios is null");
354                     return;
355                 }
356                 logd("Radios To be checked when satellite is on: " + satelliteModeRadios);
357 
358                 if (satelliteModeRadios.contains(Settings.Global.RADIO_BLUETOOTH)) {
359                     BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
360                     if (bluetoothAdapter != null) {
361                         mDisableBTOnSatelliteEnabled = true;
362                         mBTStateEnabled = bluetoothAdapter.isEnabled();
363                         radioStateIntentFilter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);
364                     }
365                 }
366 
367                 if (satelliteModeRadios.contains(Settings.Global.RADIO_NFC)) {
368                     Context applicationContext = mContext.getApplicationContext();
369                     NfcAdapter nfcAdapter = null;
370                     if (applicationContext != null) {
371                         nfcAdapter = NfcAdapter.getDefaultAdapter(mContext.getApplicationContext());
372                     }
373                     if (nfcAdapter != null) {
374                         mDisableNFCOnSatelliteEnabled = true;
375                         mNfcStateEnabled = nfcAdapter.isEnabled();
376                         radioStateIntentFilter.addAction(NfcAdapter.ACTION_ADAPTER_STATE_CHANGED);
377                     }
378                 }
379 
380                 if (satelliteModeRadios.contains(Settings.Global.RADIO_WIFI)) {
381                     WifiManager wifiManager = mContext.getSystemService(WifiManager.class);
382                     if (wifiManager != null) {
383                         mDisableWifiOnSatelliteEnabled = true;
384                         mWifiStateEnabled = wifiManager.isWifiEnabled();
385                         radioStateIntentFilter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
386                     }
387                 }
388                 mContext.registerReceiver(bTWifiNFCSateReceiver, radioStateIntentFilter);
389 
390                 if (satelliteModeRadios.contains(Settings.Global.RADIO_UWB)) {
391                     UwbManager uwbManager = mContext.getSystemService(UwbManager.class);
392                     if (uwbManager != null) {
393                         mDisableUWBOnSatelliteEnabled = true;
394                         mUwbStateEnabled = uwbManager.isUwbEnabled();
395                         final long identity = Binder.clearCallingIdentity();
396                         try {
397                             uwbManager.registerAdapterStateCallback(mContext.getMainExecutor(),
398                                     uwbAdapterStateCallback);
399                         } finally {
400                             Binder.restoreCallingIdentity(identity);
401                         }
402                     }
403                 }
404 
405                 logd("mDisableBTOnSatelliteEnabled: " + mDisableBTOnSatelliteEnabled
406                         + " mDisableNFCOnSatelliteEnabled: " + mDisableNFCOnSatelliteEnabled
407                         + " mDisableWifiOnSatelliteEnabled: " + mDisableWifiOnSatelliteEnabled
408                         + " mDisableUWBOnSatelliteEnabled: " + mDisableUWBOnSatelliteEnabled);
409 
410                 logd("mBTStateEnabled: " + mBTStateEnabled
411                         + " mNfcStateEnabled: " + mNfcStateEnabled
412                         + " mWifiStateEnabled: " + mWifiStateEnabled
413                         + " mUwbStateEnabled: " + mUwbStateEnabled);
414             }
415         }
416     }
417 
418     protected class UwbAdapterStateCallback implements UwbManager.AdapterStateCallback {
419 
toString(int state)420         public String toString(int state) {
421             switch (state) {
422                 case UwbManager.AdapterStateCallback.STATE_DISABLED:
423                     return "Disabled";
424 
425                 case UwbManager.AdapterStateCallback.STATE_ENABLED_INACTIVE:
426                     return "Inactive";
427 
428                 case UwbManager.AdapterStateCallback.STATE_ENABLED_ACTIVE:
429                     return "Active";
430 
431                 default:
432                     return "";
433             }
434         }
435 
436         @Override
onStateChanged(int state, int reason)437         public void onStateChanged(int state, int reason) {
438             logd("UwbAdapterStateCallback#onStateChanged() called, state = " + toString(state));
439             logd("Adapter state changed reason " + String.valueOf(reason));
440             synchronized (mRadioStateLock) {
441                 if (state == UwbManager.AdapterStateCallback.STATE_DISABLED) {
442                     mUwbStateEnabled = false;
443                     evaluateToSendSatelliteEnabledSuccess();
444                 } else {
445                     mUwbStateEnabled = true;
446                 }
447                 logd("mUwbStateEnabled: " + mUwbStateEnabled);
448             }
449         }
450     }
451 
452     protected class BTWifiNFCStateReceiver extends BroadcastReceiver {
453         @Override
onReceive(Context context, Intent intent)454         public void onReceive(Context context, Intent intent) {
455             final String action = intent.getAction();
456             if (action == null) {
457                 logd("BTWifiNFCStateReceiver NULL action for intent " + intent);
458                 return;
459             }
460 
461             switch (action) {
462                 case BluetoothAdapter.ACTION_STATE_CHANGED:
463                     int btState = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE,
464                             BluetoothAdapter.ERROR);
465                     synchronized (mRadioStateLock) {
466                         boolean currentBTStateEnabled = mBTStateEnabled;
467                         if (btState == BluetoothAdapter.STATE_OFF) {
468                             mBTStateEnabled = false;
469                             evaluateToSendSatelliteEnabledSuccess();
470                         } else if (btState == BluetoothAdapter.STATE_ON) {
471                             mBTStateEnabled = true;
472                         }
473                         if (currentBTStateEnabled != mBTStateEnabled) {
474                             logd("mBTStateEnabled=" + mBTStateEnabled);
475                         }
476                     }
477                     break;
478 
479                 case NfcAdapter.ACTION_ADAPTER_STATE_CHANGED:
480                     int nfcState = intent.getIntExtra(NfcAdapter.EXTRA_ADAPTER_STATE, -1);
481                     synchronized (mRadioStateLock) {
482                         boolean currentNfcStateEnabled = mNfcStateEnabled;
483                         if (nfcState == NfcAdapter.STATE_ON) {
484                             mNfcStateEnabled = true;
485                         } else if (nfcState == NfcAdapter.STATE_OFF) {
486                             mNfcStateEnabled = false;
487                             evaluateToSendSatelliteEnabledSuccess();
488                         }
489                         if (currentNfcStateEnabled != mNfcStateEnabled) {
490                             logd("mNfcStateEnabled=" + mNfcStateEnabled);
491                         }
492                     }
493                     break;
494 
495                 case WifiManager.WIFI_STATE_CHANGED_ACTION:
496                     int wifiState = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE,
497                             WifiManager.WIFI_STATE_UNKNOWN);
498                     synchronized (mRadioStateLock) {
499                         boolean currentWifiStateEnabled = mWifiStateEnabled;
500                         if (wifiState == WifiManager.WIFI_STATE_ENABLED) {
501                             mWifiStateEnabled = true;
502                         } else if (wifiState == WifiManager.WIFI_STATE_DISABLED) {
503                             mWifiStateEnabled = false;
504                             evaluateToSendSatelliteEnabledSuccess();
505                         }
506                         if (currentWifiStateEnabled != mWifiStateEnabled) {
507                             logd("mWifiStateEnabled=" + mWifiStateEnabled);
508                         }
509                     }
510                     break;
511                 default:
512                     break;
513             }
514         }
515     }
516 
517     private static final class SatelliteControllerHandlerRequest {
518         /** The argument to use for the request */
519         public @NonNull Object argument;
520         /** The caller needs to specify the phone to be used for the request */
521         public @NonNull Phone phone;
522         /** The result of the request that is run on the main thread */
523         public @Nullable Object result;
524 
SatelliteControllerHandlerRequest(Object argument, Phone phone)525         SatelliteControllerHandlerRequest(Object argument, Phone phone) {
526             this.argument = argument;
527             this.phone = phone;
528         }
529     }
530 
531     private static final class RequestSatelliteEnabledArgument {
532         public boolean enableSatellite;
533         public boolean enableDemoMode;
534         @NonNull public Consumer<Integer> callback;
535 
RequestSatelliteEnabledArgument(boolean enableSatellite, boolean enableDemoMode, Consumer<Integer> callback)536         RequestSatelliteEnabledArgument(boolean enableSatellite, boolean enableDemoMode,
537                 Consumer<Integer> callback) {
538             this.enableSatellite = enableSatellite;
539             this.enableDemoMode = enableDemoMode;
540             this.callback = callback;
541         }
542     }
543 
544     private static final class ProvisionSatelliteServiceArgument {
545         @NonNull public String token;
546         @NonNull public byte[] provisionData;
547         @NonNull public Consumer<Integer> callback;
548         public int subId;
549 
ProvisionSatelliteServiceArgument(String token, byte[] provisionData, Consumer<Integer> callback, int subId)550         ProvisionSatelliteServiceArgument(String token, byte[] provisionData,
551                 Consumer<Integer> callback, int subId) {
552             this.token = token;
553             this.provisionData = provisionData;
554             this.callback = callback;
555             this.subId = subId;
556         }
557     }
558 
559     /**
560      * Arguments to send to SatelliteTransmissionUpdate registrants
561      */
562     public static final class SatelliteTransmissionUpdateArgument {
563         @NonNull public Consumer<Integer> errorCallback;
564         @NonNull public ISatelliteTransmissionUpdateCallback callback;
565         public int subId;
566 
SatelliteTransmissionUpdateArgument(Consumer<Integer> errorCallback, ISatelliteTransmissionUpdateCallback callback, int subId)567         SatelliteTransmissionUpdateArgument(Consumer<Integer> errorCallback,
568                 ISatelliteTransmissionUpdateCallback callback, int subId) {
569             this.errorCallback = errorCallback;
570             this.callback = callback;
571             this.subId = subId;
572         }
573     }
574 
575     @Override
handleMessage(Message msg)576     public void handleMessage(Message msg) {
577         SatelliteControllerHandlerRequest request;
578         Message onCompleted;
579         AsyncResult ar;
580 
581         switch(msg.what) {
582             case CMD_START_SATELLITE_TRANSMISSION_UPDATES: {
583                 request = (SatelliteControllerHandlerRequest) msg.obj;
584                 onCompleted =
585                         obtainMessage(EVENT_START_SATELLITE_TRANSMISSION_UPDATES_DONE, request);
586                 mPointingAppController.startSatelliteTransmissionUpdates(onCompleted,
587                         request.phone);
588                 break;
589             }
590 
591             case EVENT_START_SATELLITE_TRANSMISSION_UPDATES_DONE: {
592                 handleStartSatelliteTransmissionUpdatesDone((AsyncResult) msg.obj);
593                 break;
594             }
595 
596             case CMD_STOP_SATELLITE_TRANSMISSION_UPDATES: {
597                 request = (SatelliteControllerHandlerRequest) msg.obj;
598                 onCompleted =
599                         obtainMessage(EVENT_STOP_SATELLITE_TRANSMISSION_UPDATES_DONE, request);
600                 mPointingAppController.stopSatelliteTransmissionUpdates(onCompleted, request.phone);
601                 break;
602             }
603 
604             case EVENT_STOP_SATELLITE_TRANSMISSION_UPDATES_DONE: {
605                 ar = (AsyncResult) msg.obj;
606                 request = (SatelliteControllerHandlerRequest) ar.userObj;
607                 int error =  SatelliteServiceUtils.getSatelliteError(ar,
608                         "stopSatelliteTransmissionUpdates");
609                 ((Consumer<Integer>) request.argument).accept(error);
610                 break;
611             }
612 
613             case CMD_PROVISION_SATELLITE_SERVICE: {
614                 request = (SatelliteControllerHandlerRequest) msg.obj;
615                 ProvisionSatelliteServiceArgument argument =
616                         (ProvisionSatelliteServiceArgument) request.argument;
617                 if (mSatelliteProvisionCallbacks.containsKey(argument.subId)) {
618                     argument.callback.accept(
619                             SatelliteManager.SATELLITE_SERVICE_PROVISION_IN_PROGRESS);
620                     notifyRequester(request);
621                     break;
622                 }
623                 mSatelliteProvisionCallbacks.put(argument.subId, argument.callback);
624                 onCompleted = obtainMessage(EVENT_PROVISION_SATELLITE_SERVICE_DONE, request);
625                 // Log the current time for provision triggered
626                 mProvisionMetricsStats.setProvisioningStartTime();
627                 if (mSatelliteModemInterface.isSatelliteServiceSupported()) {
628                     mSatelliteModemInterface.provisionSatelliteService(argument.token,
629                             argument.provisionData, onCompleted);
630                     break;
631                 }
632                 Phone phone = request.phone;
633                 if (phone != null) {
634                     phone.provisionSatelliteService(onCompleted, argument.token);
635                 } else {
636                     loge("provisionSatelliteService: No phone object");
637                     argument.callback.accept(SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE);
638                     notifyRequester(request);
639                     mProvisionMetricsStats
640                             .setResultCode(SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE)
641                             .reportProvisionMetrics();
642                     mControllerMetricsStats.reportProvisionCount(
643                             SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE);
644                 }
645                 break;
646             }
647 
648             case EVENT_PROVISION_SATELLITE_SERVICE_DONE: {
649                 ar = (AsyncResult) msg.obj;
650                 request = (SatelliteControllerHandlerRequest) ar.userObj;
651                 int errorCode =  SatelliteServiceUtils.getSatelliteError(ar,
652                         "provisionSatelliteService");
653                 handleEventProvisionSatelliteServiceDone(
654                         (ProvisionSatelliteServiceArgument) request.argument, errorCode);
655                 notifyRequester(request);
656                 break;
657             }
658 
659             case CMD_DEPROVISION_SATELLITE_SERVICE: {
660                 request = (SatelliteControllerHandlerRequest) msg.obj;
661                 ProvisionSatelliteServiceArgument argument =
662                         (ProvisionSatelliteServiceArgument) request.argument;
663                 onCompleted = obtainMessage(EVENT_DEPROVISION_SATELLITE_SERVICE_DONE, request);
664                 if (argument.callback != null) {
665                     mProvisionMetricsStats.setProvisioningStartTime();
666                 }
667                 if (mSatelliteModemInterface.isSatelliteServiceSupported()) {
668                     mSatelliteModemInterface
669                             .deprovisionSatelliteService(argument.token, onCompleted);
670                     break;
671                 }
672                 Phone phone = request.phone;
673                 if (phone != null) {
674                     phone.deprovisionSatelliteService(onCompleted, argument.token);
675                 } else {
676                     loge("deprovisionSatelliteService: No phone object");
677                     if (argument.callback != null) {
678                         argument.callback.accept(
679                                 SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE);
680                         mProvisionMetricsStats
681                                 .setResultCode(SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE)
682                                 .reportProvisionMetrics();
683                         mControllerMetricsStats.reportDeprovisionCount(
684                                 SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE);
685                     }
686                 }
687                 break;
688             }
689 
690             case EVENT_DEPROVISION_SATELLITE_SERVICE_DONE: {
691                 ar = (AsyncResult) msg.obj;
692                 request = (SatelliteControllerHandlerRequest) ar.userObj;
693                 int errorCode =  SatelliteServiceUtils.getSatelliteError(ar,
694                         "deprovisionSatelliteService");
695                 handleEventDeprovisionSatelliteServiceDone(
696                         (ProvisionSatelliteServiceArgument) request.argument, errorCode);
697                 break;
698             }
699 
700             case CMD_SET_SATELLITE_ENABLED: {
701                 request = (SatelliteControllerHandlerRequest) msg.obj;
702                 handleSatelliteEnabled(request);
703                 break;
704             }
705 
706             case EVENT_SET_SATELLITE_ENABLED_DONE: {
707                 ar = (AsyncResult) msg.obj;
708                 request = (SatelliteControllerHandlerRequest) ar.userObj;
709                 RequestSatelliteEnabledArgument argument =
710                         (RequestSatelliteEnabledArgument) request.argument;
711                 int error =  SatelliteServiceUtils.getSatelliteError(ar, "setSatelliteEnabled");
712                 logd("EVENT_SET_SATELLITE_ENABLED_DONE = " + error);
713 
714                 if (error == SatelliteManager.SATELLITE_ERROR_NONE) {
715                     if (argument.enableSatellite) {
716                         synchronized (mSatelliteEnabledRequestLock) {
717                             mWaitingForRadioDisabled = true;
718                         }
719                         setSettingsKeyForSatelliteMode(SATELLITE_MODE_ENABLED_TRUE);
720 
721                         /**
722                          * TODO for NTN-based satellites: Check if satellite is acquired.
723                          */
724                         if (mNeedsSatellitePointing) {
725                             mPointingAppController.startPointingUI(false);
726                         }
727                         evaluateToSendSatelliteEnabledSuccess();
728                     } else {
729                         synchronized (mSatelliteEnabledRequestLock) {
730                             if (mSatelliteEnabledRequest != null &&
731                                     mSatelliteEnabledRequest.enableSatellite == true &&
732                                     argument.enableSatellite == false && mWaitingForRadioDisabled) {
733                                 // Previous mSatelliteEnabledRequest is successful but waiting for
734                                 // all radios to be turned off.
735                                 mSatelliteEnabledRequest.callback.accept(
736                                         SatelliteManager.SATELLITE_ERROR_NONE);
737                             }
738                         }
739 
740                         synchronized (mIsSatelliteEnabledLock) {
741                             if (!mWaitingForSatelliteModemOff) {
742                                 moveSatelliteToOffStateAndCleanUpResources(
743                                         SatelliteManager.SATELLITE_ERROR_NONE, argument.callback);
744                             } else {
745                                 logd("Wait for satellite modem off before updating satellite"
746                                         + " modem state");
747                             }
748                             mWaitingForDisableSatelliteModemResponse = false;
749                         }
750                     }
751                 } else {
752                     synchronized (mSatelliteEnabledRequestLock) {
753                         if (mSatelliteEnabledRequest != null &&
754                                 mSatelliteEnabledRequest.enableSatellite == true &&
755                                 argument.enableSatellite == false && mWaitingForRadioDisabled) {
756                             // Previous mSatelliteEnabledRequest is successful but waiting for
757                             // all radios to be turned off.
758                             mSatelliteEnabledRequest.callback.accept(
759                                     SatelliteManager.SATELLITE_ERROR_NONE);
760                         }
761                     }
762                     resetSatelliteEnabledRequest();
763 
764                     // If Satellite enable/disable request returned Error, no need to wait for radio
765                     argument.callback.accept(error);
766                 }
767 
768                 if (argument.enableSatellite) {
769                     if (error == SatelliteManager.SATELLITE_ERROR_NONE) {
770                         mControllerMetricsStats.onSatelliteEnabled();
771                         mControllerMetricsStats.reportServiceEnablementSuccessCount();
772                     } else {
773                         mControllerMetricsStats.reportServiceEnablementFailCount();
774                     }
775                     SessionMetricsStats.getInstance()
776                             .setInitializationResult(error)
777                             .setRadioTechnology(SatelliteManager.NT_RADIO_TECHNOLOGY_PROPRIETARY)
778                             .reportSessionMetrics();
779                 } else {
780                     mControllerMetricsStats.onSatelliteDisabled();
781                     synchronized (mIsSatelliteEnabledLock) {
782                         mWaitingForDisableSatelliteModemResponse = false;
783                     }
784                 }
785                 break;
786             }
787 
788             case CMD_IS_SATELLITE_ENABLED: {
789                 request = (SatelliteControllerHandlerRequest) msg.obj;
790                 onCompleted = obtainMessage(EVENT_IS_SATELLITE_ENABLED_DONE, request);
791                 if (mSatelliteModemInterface.isSatelliteServiceSupported()) {
792                     mSatelliteModemInterface.requestIsSatelliteEnabled(onCompleted);
793                     break;
794                 }
795                 Phone phone = request.phone;
796                 if (phone != null) {
797                     phone.isSatellitePowerOn(onCompleted);
798                 } else {
799                     loge("isSatelliteEnabled: No phone object");
800                     ((ResultReceiver) request.argument).send(
801                             SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE, null);
802                 }
803                 break;
804             }
805 
806             case EVENT_IS_SATELLITE_ENABLED_DONE: {
807                 ar = (AsyncResult) msg.obj;
808                 request = (SatelliteControllerHandlerRequest) ar.userObj;
809                 int error =  SatelliteServiceUtils.getSatelliteError(ar,
810                         "isSatelliteEnabled");
811                 Bundle bundle = new Bundle();
812                 if (error == SatelliteManager.SATELLITE_ERROR_NONE) {
813                     if (ar.result == null) {
814                         loge("isSatelliteEnabled: result is null");
815                         error = SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE;
816                     } else {
817                         boolean enabled = ((int[]) ar.result)[0] == 1;
818                         if (DBG) logd("isSatelliteEnabled: " + enabled);
819                         bundle.putBoolean(SatelliteManager.KEY_SATELLITE_ENABLED, enabled);
820                         updateSatelliteEnabledState(enabled, "EVENT_IS_SATELLITE_ENABLED_DONE");
821                     }
822                 } else if (error == SatelliteManager.SATELLITE_REQUEST_NOT_SUPPORTED) {
823                     updateSatelliteSupportedStateWhenSatelliteServiceConnected(false);
824                 }
825                 ((ResultReceiver) request.argument).send(error, bundle);
826                 break;
827             }
828 
829             case CMD_IS_SATELLITE_SUPPORTED: {
830                 request = (SatelliteControllerHandlerRequest) msg.obj;
831                 onCompleted = obtainMessage(EVENT_IS_SATELLITE_SUPPORTED_DONE, request);
832 
833                 if (mSatelliteModemInterface.isSatelliteServiceSupported()) {
834                     mSatelliteModemInterface.requestIsSatelliteSupported(onCompleted);
835                     break;
836                 }
837                 Phone phone = request.phone;
838                 if (phone != null) {
839                     phone.isSatelliteSupported(onCompleted);
840                 } else {
841                     loge("isSatelliteSupported: No phone object");
842                     ((ResultReceiver) request.argument).send(
843                             SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE, null);
844                 }
845                 break;
846             }
847 
848             case EVENT_IS_SATELLITE_SUPPORTED_DONE: {
849                 ar = (AsyncResult) msg.obj;
850                 request = (SatelliteControllerHandlerRequest) ar.userObj;
851                 int error =  SatelliteServiceUtils.getSatelliteError(ar, "isSatelliteSupported");
852                 Bundle bundle = new Bundle();
853                 if (error == SatelliteManager.SATELLITE_ERROR_NONE) {
854                     if (ar.result == null) {
855                         loge("isSatelliteSupported: result is null");
856                         error = SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE;
857                     } else {
858                         boolean supported = (boolean) ar.result;
859                         if (DBG) logd("isSatelliteSupported: " + supported);
860                         bundle.putBoolean(SatelliteManager.KEY_SATELLITE_SUPPORTED, supported);
861                         updateSatelliteSupportedStateWhenSatelliteServiceConnected(supported);
862                     }
863                 }
864                 ((ResultReceiver) request.argument).send(error, bundle);
865                 break;
866             }
867 
868             case CMD_GET_SATELLITE_CAPABILITIES: {
869                 request = (SatelliteControllerHandlerRequest) msg.obj;
870                 onCompleted = obtainMessage(EVENT_GET_SATELLITE_CAPABILITIES_DONE, request);
871                 if (mSatelliteModemInterface.isSatelliteServiceSupported()) {
872                     mSatelliteModemInterface.requestSatelliteCapabilities(onCompleted);
873                     break;
874                 }
875                 Phone phone = request.phone;
876                 if (phone != null) {
877                     phone.getSatelliteCapabilities(onCompleted);
878                 } else {
879                     loge("getSatelliteCapabilities: No phone object");
880                     ((ResultReceiver) request.argument).send(
881                             SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE, null);
882                 }
883                 break;
884             }
885 
886             case EVENT_GET_SATELLITE_CAPABILITIES_DONE: {
887                 ar = (AsyncResult) msg.obj;
888                 request = (SatelliteControllerHandlerRequest) ar.userObj;
889                 int error =  SatelliteServiceUtils.getSatelliteError(ar,
890                         "getSatelliteCapabilities");
891                 Bundle bundle = new Bundle();
892                 if (error == SatelliteManager.SATELLITE_ERROR_NONE) {
893                     if (ar.result == null) {
894                         loge("getSatelliteCapabilities: result is null");
895                         error = SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE;
896                     } else {
897                         SatelliteCapabilities capabilities = (SatelliteCapabilities) ar.result;
898                         synchronized (mNeedsSatellitePointingLock) {
899                             mNeedsSatellitePointing = capabilities.isPointingRequired();
900                         }
901                         if (DBG) logd("getSatelliteCapabilities: " + capabilities);
902                         bundle.putParcelable(SatelliteManager.KEY_SATELLITE_CAPABILITIES,
903                                 capabilities);
904                         synchronized (mSatelliteCapabilitiesLock) {
905                             mSatelliteCapabilities = capabilities;
906                         }
907                     }
908                 }
909                 ((ResultReceiver) request.argument).send(error, bundle);
910                 break;
911             }
912 
913             case CMD_IS_SATELLITE_COMMUNICATION_ALLOWED: {
914                 request = (SatelliteControllerHandlerRequest) msg.obj;
915                 onCompleted =
916                         obtainMessage(EVENT_IS_SATELLITE_COMMUNICATION_ALLOWED_DONE, request);
917                 if (mSatelliteModemInterface.isSatelliteServiceSupported()) {
918                     mSatelliteModemInterface
919                             .requestIsSatelliteCommunicationAllowedForCurrentLocation(
920                                     onCompleted);
921                     break;
922                 }
923                 Phone phone = request.phone;
924                 if (phone != null) {
925                     phone.isSatelliteCommunicationAllowedForCurrentLocation(onCompleted);
926                 } else {
927                     loge("isSatelliteCommunicationAllowedForCurrentLocation: No phone object");
928                     ((ResultReceiver) request.argument).send(
929                             SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE, null);
930                 }
931                 break;
932             }
933 
934             case EVENT_IS_SATELLITE_COMMUNICATION_ALLOWED_DONE: {
935                 ar = (AsyncResult) msg.obj;
936                 request = (SatelliteControllerHandlerRequest) ar.userObj;
937                 int error =  SatelliteServiceUtils.getSatelliteError(ar,
938                         "isSatelliteCommunicationAllowedForCurrentLocation");
939                 Bundle bundle = new Bundle();
940                 if (error == SatelliteManager.SATELLITE_ERROR_NONE) {
941                     if (ar.result == null) {
942                         loge("isSatelliteCommunicationAllowedForCurrentLocation: result is null");
943                         error = SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE;
944                     } else {
945                         boolean communicationAllowed = (boolean) ar.result;
946                         if (DBG) {
947                             logd("isSatelliteCommunicationAllowedForCurrentLocation: "
948                                     + communicationAllowed);
949                         }
950                         bundle.putBoolean(SatelliteManager.KEY_SATELLITE_COMMUNICATION_ALLOWED,
951                                 communicationAllowed);
952                     }
953                 }
954                 ((ResultReceiver) request.argument).send(error, bundle);
955                 break;
956             }
957 
958             case CMD_GET_TIME_SATELLITE_NEXT_VISIBLE: {
959                 request = (SatelliteControllerHandlerRequest) msg.obj;
960                 onCompleted = obtainMessage(EVENT_GET_TIME_SATELLITE_NEXT_VISIBLE_DONE,
961                         request);
962                 if (mSatelliteModemInterface.isSatelliteServiceSupported()) {
963                     mSatelliteModemInterface
964                             .requestTimeForNextSatelliteVisibility(onCompleted);
965                     break;
966                 }
967                 Phone phone = request.phone;
968                 if (phone != null) {
969                     phone.requestTimeForNextSatelliteVisibility(onCompleted);
970                 } else {
971                     loge("requestTimeForNextSatelliteVisibility: No phone object");
972                     ((ResultReceiver) request.argument).send(
973                             SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE, null);
974                 }
975                 break;
976             }
977 
978             case EVENT_GET_TIME_SATELLITE_NEXT_VISIBLE_DONE: {
979                 ar = (AsyncResult) msg.obj;
980                 request = (SatelliteControllerHandlerRequest) ar.userObj;
981                 int error = SatelliteServiceUtils.getSatelliteError(ar,
982                         "requestTimeForNextSatelliteVisibility");
983                 Bundle bundle = new Bundle();
984                 if (error == SatelliteManager.SATELLITE_ERROR_NONE) {
985                     if (ar.result == null) {
986                         loge("requestTimeForNextSatelliteVisibility: result is null");
987                         error = SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE;
988                     } else {
989                         int nextVisibilityDuration = ((int[]) ar.result)[0];
990                         if (DBG) {
991                             logd("requestTimeForNextSatelliteVisibility: " +
992                                     nextVisibilityDuration);
993                         }
994                         bundle.putInt(SatelliteManager.KEY_SATELLITE_NEXT_VISIBILITY,
995                                 nextVisibilityDuration);
996                     }
997                 }
998                 ((ResultReceiver) request.argument).send(error, bundle);
999                 break;
1000             }
1001 
1002             case EVENT_RADIO_STATE_CHANGED: {
1003                 if (mCi.getRadioState() == TelephonyManager.RADIO_POWER_OFF
1004                         || mCi.getRadioState() == TelephonyManager.RADIO_POWER_UNAVAILABLE) {
1005                     mIsRadioOn = false;
1006                     logd("Radio State Changed to " + mCi.getRadioState());
1007                     if (isSatelliteEnabled()) {
1008                         IIntegerConsumer errorCallback = new IIntegerConsumer.Stub() {
1009                             @Override
1010                             public void accept(int result) {
1011                                 logd("RequestSatelliteEnabled: result=" + result);
1012                             }
1013                         };
1014                         Phone phone = SatelliteServiceUtils.getPhone();
1015                         Consumer<Integer> result = FunctionalUtils
1016                                 .ignoreRemoteException(errorCallback::accept);
1017                         RequestSatelliteEnabledArgument message =
1018                                 new RequestSatelliteEnabledArgument(false, false, result);
1019                         request = new SatelliteControllerHandlerRequest(message, phone);
1020                         handleSatelliteEnabled(request);
1021                     } else {
1022                         logd("EVENT_RADIO_STATE_CHANGED: Satellite modem is currently disabled."
1023                                 + " Ignored the event");
1024                     }
1025                 } else {
1026                     mIsRadioOn = true;
1027                     if (!mSatelliteModemInterface.isSatelliteServiceSupported()) {
1028                         synchronized (mIsSatelliteSupportedLock) {
1029                             if (mIsSatelliteSupported == null) {
1030                                 ResultReceiver receiver = new ResultReceiver(this) {
1031                                     @Override
1032                                     protected void onReceiveResult(
1033                                             int resultCode, Bundle resultData) {
1034                                         logd("requestIsSatelliteSupported: resultCode="
1035                                                 + resultCode);
1036                                     }
1037                                 };
1038                                 requestIsSatelliteSupported(
1039                                         SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, receiver);
1040                             }
1041                         }
1042                     } else {
1043                         logd("EVENT_RADIO_STATE_CHANGED: Satellite vendor service is supported."
1044                                 + " Ignored the event");
1045                     }
1046                 }
1047                 break;
1048             }
1049 
1050             case CMD_IS_SATELLITE_PROVISIONED: {
1051                 request = (SatelliteControllerHandlerRequest) msg.obj;
1052                 onCompleted = obtainMessage(EVENT_IS_SATELLITE_PROVISIONED_DONE, request);
1053                 if (mSatelliteModemInterface.isSatelliteServiceSupported()) {
1054                     mSatelliteModemInterface.requestIsSatelliteProvisioned(onCompleted);
1055                     break;
1056                 }
1057                 Phone phone = request.phone;
1058                 if (phone != null) {
1059                     phone.isSatelliteProvisioned(onCompleted);
1060                 } else {
1061                     loge("isSatelliteProvisioned: No phone object");
1062                     ((ResultReceiver) request.argument).send(
1063                             SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE, null);
1064                 }
1065                 break;
1066             }
1067 
1068             case EVENT_IS_SATELLITE_PROVISIONED_DONE: {
1069                 ar = (AsyncResult) msg.obj;
1070                 request = (SatelliteControllerHandlerRequest) ar.userObj;
1071                 int error =  SatelliteServiceUtils.getSatelliteError(ar,
1072                         "isSatelliteProvisioned");
1073                 Bundle bundle = new Bundle();
1074                 if (error == SatelliteManager.SATELLITE_ERROR_NONE) {
1075                     if (ar.result == null) {
1076                         loge("isSatelliteProvisioned: result is null");
1077                         error = SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE;
1078                     } else {
1079                         boolean provisioned = ((int[]) ar.result)[0] == 1;
1080                         if (DBG) logd("isSatelliteProvisioned: " + provisioned);
1081                         bundle.putBoolean(SatelliteManager.KEY_SATELLITE_PROVISIONED, provisioned);
1082                         synchronized (mIsSatelliteProvisionedLock) {
1083                             mIsSatelliteProvisioned = provisioned;
1084                         }
1085                     }
1086                 }
1087                 ((ResultReceiver) request.argument).send(error, bundle);
1088                 break;
1089             }
1090 
1091             case EVENT_SATELLITE_PROVISION_STATE_CHANGED:
1092                 ar = (AsyncResult) msg.obj;
1093                 if (ar.result == null) {
1094                     loge("EVENT_SATELLITE_PROVISION_STATE_CHANGED: result is null");
1095                 } else {
1096                     handleEventSatelliteProvisionStateChanged((boolean) ar.result);
1097                 }
1098                 break;
1099 
1100             case EVENT_PENDING_DATAGRAMS:
1101                 logd("Received EVENT_PENDING_DATAGRAMS");
1102                 IIntegerConsumer internalCallback = new IIntegerConsumer.Stub() {
1103                     @Override
1104                     public void accept(int result) {
1105                         logd("pollPendingSatelliteDatagram result: " + result);
1106                     }
1107                 };
1108                 pollPendingSatelliteDatagrams(
1109                         SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, internalCallback);
1110                 break;
1111 
1112             case EVENT_SATELLITE_MODEM_STATE_CHANGED:
1113                 ar = (AsyncResult) msg.obj;
1114                 if (ar.result == null) {
1115                     loge("EVENT_SATELLITE_MODEM_STATE_CHANGED: result is null");
1116                 } else {
1117                     handleEventSatelliteModemStateChanged((int) ar.result);
1118                 }
1119                 break;
1120 
1121             default:
1122                 Log.w(TAG, "SatelliteControllerHandler: unexpected message code: " +
1123                         msg.what);
1124                 break;
1125         }
1126     }
1127 
notifyRequester(SatelliteControllerHandlerRequest request)1128     private void notifyRequester(SatelliteControllerHandlerRequest request) {
1129         synchronized (request) {
1130             request.notifyAll();
1131         }
1132     }
1133 
1134     /**
1135      * Request to enable or disable the satellite modem and demo mode. If the satellite modem is
1136      * enabled, this will also disable the cellular modem, and if the satellite modem is disabled,
1137      * this will also re-enable the cellular modem.
1138      *
1139      * @param subId The subId of the subscription to set satellite enabled for.
1140      * @param enableSatellite {@code true} to enable the satellite modem and
1141      *                        {@code false} to disable.
1142      * @param enableDemoMode {@code true} to enable demo mode and {@code false} to disable.
1143      * @param callback The callback to get the error code of the request.
1144      */
requestSatelliteEnabled(int subId, boolean enableSatellite, boolean enableDemoMode, @NonNull IIntegerConsumer callback)1145     public void requestSatelliteEnabled(int subId, boolean enableSatellite, boolean enableDemoMode,
1146             @NonNull IIntegerConsumer callback) {
1147         logd("requestSatelliteEnabled subId: " + subId + " enableSatellite: " + enableSatellite
1148                 + " enableDemoMode: " + enableDemoMode);
1149 
1150         Consumer<Integer> result = FunctionalUtils.ignoreRemoteException(callback::accept);
1151 
1152         Boolean satelliteSupported = isSatelliteSupportedInternal();
1153         if (satelliteSupported == null) {
1154             result.accept(SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE);
1155             return;
1156         }
1157         if (!satelliteSupported) {
1158             result.accept(SatelliteManager.SATELLITE_NOT_SUPPORTED);
1159             return;
1160         }
1161 
1162         Boolean satelliteProvisioned = isSatelliteProvisioned();
1163         if (satelliteProvisioned == null) {
1164             result.accept(SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE);
1165             return;
1166         }
1167         if (!satelliteProvisioned) {
1168             result.accept(SatelliteManager.SATELLITE_SERVICE_NOT_PROVISIONED);
1169             return;
1170         }
1171 
1172         if (enableSatellite) {
1173             if (!mIsRadioOn) {
1174                 loge("Radio is not on, can not enable satellite");
1175                 result.accept(SatelliteManager.SATELLITE_INVALID_MODEM_STATE);
1176                 return;
1177             }
1178         } else {
1179             /* if disable satellite, always assume demo is also disabled */
1180             enableDemoMode = false;
1181         }
1182 
1183         synchronized (mIsSatelliteEnabledLock) {
1184             if (mIsSatelliteEnabled != null) {
1185                 if (mIsSatelliteEnabled == enableSatellite) {
1186                     if (enableDemoMode != mIsDemoModeEnabled) {
1187                         loge("Received invalid demo mode while satellite session is enabled"
1188                                 + " enableDemoMode = " + enableDemoMode);
1189                         result.accept(SatelliteManager.SATELLITE_INVALID_ARGUMENTS);
1190                         return;
1191                     } else {
1192                         logd("Enable request matches with current state"
1193                                 + " enableSatellite = " + enableSatellite);
1194                         result.accept(SatelliteManager.SATELLITE_ERROR_NONE);
1195                         return;
1196                     }
1197                 }
1198             }
1199         }
1200 
1201         RequestSatelliteEnabledArgument request =
1202                 new RequestSatelliteEnabledArgument(enableSatellite, enableDemoMode, result);
1203         /**
1204          * Multiple satellite enabled requests are handled as below:
1205          * 1. If there are no ongoing requests, store current request in mSatelliteEnabledRequest
1206          * 2. If there is a ongoing request, then:
1207          *      1. ongoing request = enable, current request = enable: return IN_PROGRESS error
1208          *      2. ongoing request = disable, current request = disable: return IN_PROGRESS error
1209          *      3. ongoing request = disable, current request = enable: return SATELLITE_ERROR error
1210          *      4. ongoing request = enable, current request = disable: send request to modem
1211          */
1212         synchronized (mSatelliteEnabledRequestLock) {
1213             if (mSatelliteEnabledRequest == null) {
1214                 mSatelliteEnabledRequest = request;
1215             } else if (mSatelliteEnabledRequest.enableSatellite == request.enableSatellite) {
1216                 logd("requestSatelliteEnabled enableSatellite: " + enableSatellite
1217                         + " is already in progress.");
1218                 result.accept(SatelliteManager.SATELLITE_REQUEST_IN_PROGRESS);
1219                 return;
1220             } else if (mSatelliteEnabledRequest.enableSatellite == false
1221                     && request.enableSatellite == true) {
1222                 logd("requestSatelliteEnabled enableSatellite: " + enableSatellite + " cannot be "
1223                         + "processed. Disable satellite is already in progress.");
1224                 result.accept(SatelliteManager.SATELLITE_ERROR);
1225                 return;
1226             }
1227         }
1228 
1229         sendRequestAsync(CMD_SET_SATELLITE_ENABLED, request, SatelliteServiceUtils.getPhone());
1230     }
1231 
1232     /**
1233      * Request to get whether the satellite modem is enabled.
1234      *
1235      * @param subId The subId of the subscription to check whether satellite is enabled for.
1236      * @param result The result receiver that returns whether the satellite modem is enabled
1237      *               if the request is successful or an error code if the request failed.
1238      */
requestIsSatelliteEnabled(int subId, @NonNull ResultReceiver result)1239     public void requestIsSatelliteEnabled(int subId, @NonNull ResultReceiver result) {
1240         Boolean satelliteSupported = isSatelliteSupportedInternal();
1241         if (satelliteSupported == null) {
1242             result.send(SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE, null);
1243             return;
1244         }
1245         if (!satelliteSupported) {
1246             result.send(SatelliteManager.SATELLITE_NOT_SUPPORTED, null);
1247             return;
1248         }
1249 
1250         synchronized (mIsSatelliteEnabledLock) {
1251             if (mIsSatelliteEnabled != null) {
1252                 /* We have already successfully queried the satellite modem. */
1253                 Bundle bundle = new Bundle();
1254                 bundle.putBoolean(SatelliteManager.KEY_SATELLITE_ENABLED, mIsSatelliteEnabled);
1255                 result.send(SatelliteManager.SATELLITE_ERROR_NONE, bundle);
1256                 return;
1257             }
1258         }
1259 
1260         sendRequestAsync(CMD_IS_SATELLITE_ENABLED, result, SatelliteServiceUtils.getPhone());
1261     }
1262 
1263     /**
1264      * Get whether the satellite modem is enabled.
1265      * This will return the cached value instead of querying the satellite modem.
1266      *
1267      * @return {@code true} if the satellite modem is enabled and {@code false} otherwise.
1268      */
isSatelliteEnabled()1269     public boolean isSatelliteEnabled() {
1270         if (mIsSatelliteEnabled == null) return false;
1271         return mIsSatelliteEnabled;
1272     }
1273 
1274     /**
1275      * Request to get whether the satellite service demo mode is enabled.
1276      *
1277      * @param subId The subId of the subscription to check whether the satellite demo mode
1278      *              is enabled for.
1279      * @param result The result receiver that returns whether the satellite demo mode is enabled
1280      *               if the request is successful or an error code if the request failed.
1281      */
requestIsDemoModeEnabled(int subId, @NonNull ResultReceiver result)1282     public void requestIsDemoModeEnabled(int subId, @NonNull ResultReceiver result) {
1283         Boolean satelliteSupported = isSatelliteSupportedInternal();
1284         if (satelliteSupported == null) {
1285             result.send(SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE, null);
1286             return;
1287         }
1288         if (!satelliteSupported) {
1289             result.send(SatelliteManager.SATELLITE_NOT_SUPPORTED, null);
1290             return;
1291         }
1292 
1293         Boolean satelliteProvisioned = isSatelliteProvisioned();
1294         if (satelliteProvisioned == null) {
1295             result.send(SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE, null);
1296             return;
1297         }
1298         if (!satelliteProvisioned) {
1299             result.send(SatelliteManager.SATELLITE_SERVICE_NOT_PROVISIONED, null);
1300             return;
1301         }
1302 
1303         final Bundle bundle = new Bundle();
1304         bundle.putBoolean(SatelliteManager.KEY_DEMO_MODE_ENABLED, mIsDemoModeEnabled);
1305         result.send(SatelliteManager.SATELLITE_ERROR_NONE, bundle);
1306     }
1307 
1308     /**
1309      * Get whether the satellite service demo mode is enabled.
1310      *
1311      * @return {@code true} if the satellite demo mode is enabled and {@code false} otherwise.
1312      */
isDemoModeEnabled()1313     public boolean isDemoModeEnabled() {
1314         return mIsDemoModeEnabled;
1315     }
1316 
1317     /**
1318      * Request to get whether the satellite service is supported on the device.
1319      *
1320      * @param subId The subId of the subscription to check satellite service support for.
1321      * @param result The result receiver that returns whether the satellite service is supported on
1322      *               the device if the request is successful or an error code if the request failed.
1323      */
requestIsSatelliteSupported(int subId, @NonNull ResultReceiver result)1324     public void requestIsSatelliteSupported(int subId, @NonNull ResultReceiver result) {
1325         synchronized (mIsSatelliteSupportedLock) {
1326             if (mIsSatelliteSupported != null) {
1327                 /* We have already successfully queried the satellite modem. */
1328                 Bundle bundle = new Bundle();
1329                 bundle.putBoolean(SatelliteManager.KEY_SATELLITE_SUPPORTED, mIsSatelliteSupported);
1330                 result.send(SatelliteManager.SATELLITE_ERROR_NONE, bundle);
1331                 return;
1332             }
1333         }
1334 
1335         sendRequestAsync(CMD_IS_SATELLITE_SUPPORTED, result, SatelliteServiceUtils.getPhone());
1336     }
1337 
1338     /**
1339      * Request to get the {@link SatelliteCapabilities} of the satellite service.
1340      *
1341      * @param subId The subId of the subscription to get the satellite capabilities for.
1342      * @param result The result receiver that returns the {@link SatelliteCapabilities}
1343      *               if the request is successful or an error code if the request failed.
1344      */
requestSatelliteCapabilities(int subId, @NonNull ResultReceiver result)1345     public void requestSatelliteCapabilities(int subId, @NonNull ResultReceiver result) {
1346         Boolean satelliteSupported = isSatelliteSupportedInternal();
1347         if (satelliteSupported == null) {
1348             result.send(SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE, null);
1349             return;
1350         }
1351         if (!satelliteSupported) {
1352             result.send(SatelliteManager.SATELLITE_NOT_SUPPORTED, null);
1353             return;
1354         }
1355 
1356         synchronized (mSatelliteCapabilitiesLock) {
1357             if (mSatelliteCapabilities != null) {
1358                 Bundle bundle = new Bundle();
1359                 bundle.putParcelable(SatelliteManager.KEY_SATELLITE_CAPABILITIES,
1360                         mSatelliteCapabilities);
1361                 result.send(SatelliteManager.SATELLITE_ERROR_NONE, bundle);
1362                 return;
1363             }
1364         }
1365 
1366         sendRequestAsync(CMD_GET_SATELLITE_CAPABILITIES, result, SatelliteServiceUtils.getPhone());
1367     }
1368 
1369     /**
1370      * Start receiving satellite transmission updates.
1371      * This can be called by the pointing UI when the user starts pointing to the satellite.
1372      * Modem should continue to report the pointing input as the device or satellite moves.
1373      *
1374      * @param subId The subId of the subscription to start satellite transmission updates for.
1375      * @param errorCallback The callback to get the error code of the request.
1376      * @param callback The callback to notify of satellite transmission updates.
1377      */
startSatelliteTransmissionUpdates(int subId, @NonNull IIntegerConsumer errorCallback, @NonNull ISatelliteTransmissionUpdateCallback callback)1378     public void startSatelliteTransmissionUpdates(int subId,
1379             @NonNull IIntegerConsumer errorCallback,
1380             @NonNull ISatelliteTransmissionUpdateCallback callback) {
1381         Consumer<Integer> result = FunctionalUtils.ignoreRemoteException(errorCallback::accept);
1382         Boolean satelliteSupported = isSatelliteSupportedInternal();
1383         if (satelliteSupported == null) {
1384             result.accept(SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE);
1385             return;
1386         }
1387         if (!satelliteSupported) {
1388             result.accept(SatelliteManager.SATELLITE_NOT_SUPPORTED);
1389             return;
1390         }
1391 
1392         Boolean satelliteProvisioned = isSatelliteProvisioned();
1393         if (satelliteProvisioned == null) {
1394             result.accept(SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE);
1395             return;
1396         }
1397         if (!satelliteProvisioned) {
1398             result.accept(SatelliteManager.SATELLITE_SERVICE_NOT_PROVISIONED);
1399             return;
1400         }
1401 
1402         Phone phone = SatelliteServiceUtils.getPhone();
1403         final int validSubId = SatelliteServiceUtils.getValidSatelliteSubId(subId, mContext);
1404         mPointingAppController.registerForSatelliteTransmissionUpdates(validSubId, callback, phone);
1405         sendRequestAsync(CMD_START_SATELLITE_TRANSMISSION_UPDATES,
1406                 new SatelliteTransmissionUpdateArgument(result, callback, validSubId), phone);
1407     }
1408 
1409     /**
1410      * Stop receiving satellite transmission updates.
1411      * This can be called by the pointing UI when the user stops pointing to the satellite.
1412      *
1413      * @param subId The subId of the subscription to stop satellite transmission updates for.
1414      * @param errorCallback The callback to get the error code of the request.
1415      * @param callback The callback that was passed to {@link #startSatelliteTransmissionUpdates(
1416      *                 int, IIntegerConsumer, ISatelliteTransmissionUpdateCallback)}.
1417      */
stopSatelliteTransmissionUpdates(int subId, @NonNull IIntegerConsumer errorCallback, @NonNull ISatelliteTransmissionUpdateCallback callback)1418     public void stopSatelliteTransmissionUpdates(int subId, @NonNull IIntegerConsumer errorCallback,
1419             @NonNull ISatelliteTransmissionUpdateCallback callback) {
1420         Consumer<Integer> result = FunctionalUtils.ignoreRemoteException(errorCallback::accept);
1421         Boolean satelliteSupported = isSatelliteSupportedInternal();
1422         if (satelliteSupported == null) {
1423             result.accept(SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE);
1424             return;
1425         }
1426         if (!satelliteSupported) {
1427             result.accept(SatelliteManager.SATELLITE_NOT_SUPPORTED);
1428             return;
1429         }
1430 
1431         Boolean satelliteProvisioned = isSatelliteProvisioned();
1432         if (satelliteProvisioned == null) {
1433             result.accept(SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE);
1434             return;
1435         }
1436         if (!satelliteProvisioned) {
1437             result.accept(SatelliteManager.SATELLITE_SERVICE_NOT_PROVISIONED);
1438             return;
1439         }
1440 
1441         Phone phone = SatelliteServiceUtils.getPhone();
1442         final int validSubId = SatelliteServiceUtils.getValidSatelliteSubId(subId, mContext);
1443         mPointingAppController.unregisterForSatelliteTransmissionUpdates(
1444                 validSubId, result, callback, phone);
1445 
1446         // Even if handler is null - which means there are no listeners, the modem command to stop
1447         // satellite transmission updates might have failed. The callers might want to retry
1448         // sending the command. Thus, we always need to send this command to the modem.
1449         sendRequestAsync(CMD_STOP_SATELLITE_TRANSMISSION_UPDATES, result, phone);
1450     }
1451 
1452     /**
1453      * Register the subscription with a satellite provider.
1454      * This is needed to register the subscription if the provider allows dynamic registration.
1455      *
1456      * @param subId The subId of the subscription to be provisioned.
1457      * @param token The token to be used as a unique identifier for provisioning with satellite
1458      *              gateway.
1459      * @param provisionData Data from the provisioning app that can be used by provisioning server
1460      * @param callback The callback to get the error code of the request.
1461      *
1462      * @return The signal transport used by the caller to cancel the provision request,
1463      *         or {@code null} if the request failed.
1464      */
provisionSatelliteService(int subId, @NonNull String token, @NonNull byte[] provisionData, @NonNull IIntegerConsumer callback)1465     @Nullable public ICancellationSignal provisionSatelliteService(int subId,
1466             @NonNull String token, @NonNull byte[] provisionData,
1467             @NonNull IIntegerConsumer callback) {
1468         Consumer<Integer> result = FunctionalUtils.ignoreRemoteException(callback::accept);
1469         Boolean satelliteSupported = isSatelliteSupportedInternal();
1470         if (satelliteSupported == null) {
1471             result.accept(SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE);
1472             return null;
1473         }
1474         if (!satelliteSupported) {
1475             result.accept(SatelliteManager.SATELLITE_NOT_SUPPORTED);
1476             return null;
1477         }
1478 
1479         final int validSubId = SatelliteServiceUtils.getValidSatelliteSubId(subId, mContext);
1480         if (mSatelliteProvisionCallbacks.containsKey(validSubId)) {
1481             result.accept(SatelliteManager.SATELLITE_SERVICE_PROVISION_IN_PROGRESS);
1482             return null;
1483         }
1484 
1485         Boolean satelliteProvisioned = isSatelliteProvisioned();
1486         if (satelliteProvisioned != null && satelliteProvisioned) {
1487             result.accept(SatelliteManager.SATELLITE_ERROR_NONE);
1488             return null;
1489         }
1490 
1491         Phone phone = SatelliteServiceUtils.getPhone();
1492         sendRequestAsync(CMD_PROVISION_SATELLITE_SERVICE,
1493                 new ProvisionSatelliteServiceArgument(token, provisionData, result, validSubId),
1494                 phone);
1495 
1496         ICancellationSignal cancelTransport = CancellationSignal.createTransport();
1497         CancellationSignal.fromTransport(cancelTransport).setOnCancelListener(() -> {
1498             sendRequestAsync(CMD_DEPROVISION_SATELLITE_SERVICE,
1499                     new ProvisionSatelliteServiceArgument(token, provisionData, null,
1500                             validSubId), phone);
1501             mProvisionMetricsStats.setIsCanceled(true);
1502         });
1503         return cancelTransport;
1504     }
1505 
1506     /**
1507      * Unregister the device/subscription with the satellite provider.
1508      * This is needed if the provider allows dynamic registration. Once deprovisioned,
1509      * {@link android.telephony.satellite.SatelliteProvisionStateCallback
1510      * #onSatelliteProvisionStateChanged(boolean)}
1511      * should report as deprovisioned.
1512      *
1513      * @param subId The subId of the subscription to be deprovisioned.
1514      * @param token The token of the device/subscription to be deprovisioned.
1515      * @param callback The callback to get the error code of the request.
1516      */
deprovisionSatelliteService(int subId, @NonNull String token, @NonNull IIntegerConsumer callback)1517     public void deprovisionSatelliteService(int subId,
1518             @NonNull String token, @NonNull IIntegerConsumer callback) {
1519         Consumer<Integer> result = FunctionalUtils.ignoreRemoteException(callback::accept);
1520         Boolean satelliteSupported = isSatelliteSupportedInternal();
1521         if (satelliteSupported == null) {
1522             result.accept(SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE);
1523             return;
1524         }
1525         if (!satelliteSupported) {
1526             result.accept(SatelliteManager.SATELLITE_NOT_SUPPORTED);
1527             return;
1528         }
1529 
1530         Boolean satelliteProvisioned = isSatelliteProvisioned();
1531         if (satelliteProvisioned == null) {
1532             result.accept(SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE);
1533             return;
1534         }
1535         if (!satelliteProvisioned) {
1536             result.accept(SatelliteManager.SATELLITE_ERROR_NONE);
1537             return;
1538         }
1539 
1540         Phone phone = SatelliteServiceUtils.getPhone();
1541         final int validSubId = SatelliteServiceUtils.getValidSatelliteSubId(subId, mContext);
1542         sendRequestAsync(CMD_DEPROVISION_SATELLITE_SERVICE,
1543                 new ProvisionSatelliteServiceArgument(token, null, result, validSubId),
1544                 phone);
1545     }
1546 
1547     /**
1548      * Registers for the satellite provision state changed.
1549      *
1550      * @param subId The subId of the subscription to register for provision state changed.
1551      * @param callback The callback to handle the satellite provision state changed event.
1552      *
1553      * @return The {@link SatelliteManager.SatelliteError} result of the operation.
1554      */
registerForSatelliteProvisionStateChanged(int subId, @NonNull ISatelliteProvisionStateCallback callback)1555     @SatelliteManager.SatelliteError public int registerForSatelliteProvisionStateChanged(int subId,
1556             @NonNull ISatelliteProvisionStateCallback callback) {
1557         Boolean satelliteSupported = isSatelliteSupportedInternal();
1558         if (satelliteSupported == null) {
1559             return SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE;
1560         }
1561         if (!satelliteSupported) {
1562             return SatelliteManager.SATELLITE_NOT_SUPPORTED;
1563         }
1564 
1565         mSatelliteProvisionStateChangedListeners.put(callback.asBinder(), callback);
1566         return SatelliteManager.SATELLITE_ERROR_NONE;
1567     }
1568 
1569     /**
1570      * Unregisters for the satellite provision state changed.
1571      * If callback was not registered before, the request will be ignored.
1572      *
1573      * @param subId The subId of the subscription to unregister for provision state changed.
1574      * @param callback The callback that was passed to
1575      * {@link #registerForSatelliteProvisionStateChanged(int, ISatelliteProvisionStateCallback)}.
1576      */
unregisterForSatelliteProvisionStateChanged( int subId, @NonNull ISatelliteProvisionStateCallback callback)1577     public void unregisterForSatelliteProvisionStateChanged(
1578             int subId, @NonNull ISatelliteProvisionStateCallback callback) {
1579         mSatelliteProvisionStateChangedListeners.remove(callback.asBinder());
1580     }
1581 
1582     /**
1583      * Request to get whether the device is provisioned with a satellite provider.
1584      *
1585      * @param subId The subId of the subscription to get whether the device is provisioned for.
1586      * @param result The result receiver that returns whether the device is provisioned with a
1587      *               satellite provider if the request is successful or an error code if the
1588      *               request failed.
1589      */
requestIsSatelliteProvisioned(int subId, @NonNull ResultReceiver result)1590     public void requestIsSatelliteProvisioned(int subId, @NonNull ResultReceiver result) {
1591         Boolean satelliteSupported = isSatelliteSupportedInternal();
1592         if (satelliteSupported == null) {
1593             result.send(SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE, null);
1594             return;
1595         }
1596         if (!satelliteSupported) {
1597             result.send(SatelliteManager.SATELLITE_NOT_SUPPORTED, null);
1598             return;
1599         }
1600 
1601         synchronized (mIsSatelliteProvisionedLock) {
1602             if (mIsSatelliteProvisioned != null) {
1603                 Bundle bundle = new Bundle();
1604                 bundle.putBoolean(SatelliteManager.KEY_SATELLITE_PROVISIONED,
1605                         mIsSatelliteProvisioned);
1606                 result.send(SatelliteManager.SATELLITE_ERROR_NONE, bundle);
1607                 return;
1608             }
1609         }
1610 
1611         sendRequestAsync(CMD_IS_SATELLITE_PROVISIONED, result, SatelliteServiceUtils.getPhone());
1612     }
1613 
1614     /**
1615      * Registers for modem state changed from satellite modem.
1616      *
1617      * @param subId The subId of the subscription to register for satellite modem state changed.
1618      * @param callback The callback to handle the satellite modem state changed event.
1619      *
1620      * @return The {@link SatelliteManager.SatelliteError} result of the operation.
1621      */
registerForSatelliteModemStateChanged(int subId, @NonNull ISatelliteStateCallback callback)1622     @SatelliteManager.SatelliteError public int registerForSatelliteModemStateChanged(int subId,
1623             @NonNull ISatelliteStateCallback callback) {
1624         if (mSatelliteSessionController != null) {
1625             mSatelliteSessionController.registerForSatelliteModemStateChanged(callback);
1626         } else {
1627             loge("registerForSatelliteModemStateChanged: mSatelliteSessionController"
1628                     + " is not initialized yet");
1629             return SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE;
1630         }
1631         return SatelliteManager.SATELLITE_ERROR_NONE;
1632     }
1633 
1634     /**
1635      * Unregisters for modem state changed from satellite modem.
1636      * If callback was not registered before, the request will be ignored.
1637      *
1638      * @param subId The subId of the subscription to unregister for satellite modem state changed.
1639      * @param callback The callback that was passed to
1640      *                 {@link #registerForSatelliteModemStateChanged(int, ISatelliteStateCallback)}.
1641      */
unregisterForSatelliteModemStateChanged(int subId, @NonNull ISatelliteStateCallback callback)1642     public void unregisterForSatelliteModemStateChanged(int subId,
1643             @NonNull ISatelliteStateCallback callback) {
1644         if (mSatelliteSessionController != null) {
1645             mSatelliteSessionController.unregisterForSatelliteModemStateChanged(callback);
1646         } else {
1647             loge("registerForSatelliteModemStateChanged: mSatelliteSessionController"
1648                     + " is not initialized yet");
1649         }
1650     }
1651 
1652     /**
1653      * Register to receive incoming datagrams over satellite.
1654      *
1655      * @param subId The subId of the subscription to register for incoming satellite datagrams.
1656      * @param callback The callback to handle incoming datagrams over satellite.
1657      *
1658      * @return The {@link SatelliteManager.SatelliteError} result of the operation.
1659      */
registerForSatelliteDatagram(int subId, @NonNull ISatelliteDatagramCallback callback)1660     @SatelliteManager.SatelliteError public int registerForSatelliteDatagram(int subId,
1661             @NonNull ISatelliteDatagramCallback callback) {
1662         return mDatagramController.registerForSatelliteDatagram(subId, callback);
1663     }
1664 
1665     /**
1666      * Unregister to stop receiving incoming datagrams over satellite.
1667      * If callback was not registered before, the request will be ignored.
1668      *
1669      * @param subId The subId of the subscription to unregister for incoming satellite datagrams.
1670      * @param callback The callback that was passed to
1671      *                 {@link #registerForSatelliteDatagram(int, ISatelliteDatagramCallback)}.
1672      */
unregisterForSatelliteDatagram(int subId, @NonNull ISatelliteDatagramCallback callback)1673     public void unregisterForSatelliteDatagram(int subId,
1674             @NonNull ISatelliteDatagramCallback callback) {
1675         mDatagramController.unregisterForSatelliteDatagram(subId, callback);
1676     }
1677 
1678     /**
1679      * Poll pending satellite datagrams over satellite.
1680      *
1681      * This method requests modem to check if there are any pending datagrams to be received over
1682      * satellite. If there are any incoming datagrams, they will be received via
1683      * {@link android.telephony.satellite.SatelliteDatagramCallback#onSatelliteDatagramReceived(
1684      * long, SatelliteDatagram, int, Consumer)}
1685      *
1686      * @param subId The subId of the subscription used for receiving datagrams.
1687      * @param callback The callback to get {@link SatelliteManager.SatelliteError} of the request.
1688      */
pollPendingSatelliteDatagrams(int subId, @NonNull IIntegerConsumer callback)1689     public void pollPendingSatelliteDatagrams(int subId, @NonNull IIntegerConsumer callback) {
1690         Consumer<Integer> result = FunctionalUtils.ignoreRemoteException(callback::accept);
1691 
1692         Boolean satelliteProvisioned = isSatelliteProvisioned();
1693         if (satelliteProvisioned == null) {
1694             result.accept(SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE);
1695             return;
1696         }
1697         if (!satelliteProvisioned) {
1698             result.accept(SatelliteManager.SATELLITE_SERVICE_NOT_PROVISIONED);
1699             return;
1700         }
1701 
1702         final int validSubId = SatelliteServiceUtils.getValidSatelliteSubId(subId, mContext);
1703         mDatagramController.pollPendingSatelliteDatagrams(validSubId, result);
1704     }
1705 
1706     /**
1707      * Send datagram over satellite.
1708      *
1709      * Gateway encodes SOS message or location sharing message into a datagram and passes it as
1710      * input to this method. Datagram received here will be passed down to modem without any
1711      * encoding or encryption.
1712      *
1713      * @param subId The subId of the subscription to send satellite datagrams for.
1714      * @param datagramType datagram type indicating whether the datagram is of type
1715      *                     SOS_SMS or LOCATION_SHARING.
1716      * @param datagram encoded gateway datagram which is encrypted by the caller.
1717      *                 Datagram will be passed down to modem without any encoding or encryption.
1718      * @param needFullScreenPointingUI this is used to indicate pointingUI app to open in
1719      *                                 full screen mode.
1720      * @param callback The callback to get {@link SatelliteManager.SatelliteError} of the request.
1721      */
sendSatelliteDatagram(int subId, @SatelliteManager.DatagramType int datagramType, SatelliteDatagram datagram, boolean needFullScreenPointingUI, @NonNull IIntegerConsumer callback)1722     public void sendSatelliteDatagram(int subId, @SatelliteManager.DatagramType int datagramType,
1723             SatelliteDatagram datagram, boolean needFullScreenPointingUI,
1724             @NonNull IIntegerConsumer callback) {
1725         Consumer<Integer> result = FunctionalUtils.ignoreRemoteException(callback::accept);
1726 
1727         Boolean satelliteProvisioned = isSatelliteProvisioned();
1728         if (satelliteProvisioned == null) {
1729             result.accept(SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE);
1730             return;
1731         }
1732         if (!satelliteProvisioned) {
1733             result.accept(SatelliteManager.SATELLITE_SERVICE_NOT_PROVISIONED);
1734             return;
1735         }
1736 
1737         /**
1738          * TODO for NTN-based satellites: Check if satellite is acquired.
1739          */
1740         if (mNeedsSatellitePointing) {
1741             mPointingAppController.startPointingUI(needFullScreenPointingUI);
1742         }
1743 
1744         final int validSubId = SatelliteServiceUtils.getValidSatelliteSubId(subId, mContext);
1745         mDatagramController.sendSatelliteDatagram(validSubId, datagramType, datagram,
1746                 needFullScreenPointingUI, result);
1747     }
1748 
1749     /**
1750      * Request to get whether satellite communication is allowed for the current location.
1751      *
1752      * @param subId The subId of the subscription to check whether satellite communication is
1753      *              allowed for the current location for.
1754      * @param result The result receiver that returns whether satellite communication is allowed
1755      *               for the current location if the request is successful or an error code
1756      *               if the request failed.
1757      */
requestIsSatelliteCommunicationAllowedForCurrentLocation(int subId, @NonNull ResultReceiver result)1758     public void requestIsSatelliteCommunicationAllowedForCurrentLocation(int subId,
1759             @NonNull ResultReceiver result) {
1760         Boolean satelliteSupported = isSatelliteSupportedInternal();
1761         if (satelliteSupported == null) {
1762             result.send(SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE, null);
1763             return;
1764         }
1765         if (!satelliteSupported) {
1766             result.send(SatelliteManager.SATELLITE_NOT_SUPPORTED, null);
1767             return;
1768         }
1769 
1770         sendRequestAsync(
1771                 CMD_IS_SATELLITE_COMMUNICATION_ALLOWED, result, SatelliteServiceUtils.getPhone());
1772     }
1773 
1774     /**
1775      * Request to get the time after which the satellite will be visible.
1776      *
1777      * @param subId The subId to get the time after which the satellite will be visible for.
1778      * @param result The result receiver that returns the time after which the satellite will
1779      *               be visible if the request is successful or an error code if the request failed.
1780      */
requestTimeForNextSatelliteVisibility(int subId, @NonNull ResultReceiver result)1781     public void requestTimeForNextSatelliteVisibility(int subId, @NonNull ResultReceiver result) {
1782         Boolean satelliteSupported = isSatelliteSupportedInternal();
1783         if (satelliteSupported == null) {
1784             result.send(SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE, null);
1785             return;
1786         }
1787         if (!satelliteSupported) {
1788             result.send(SatelliteManager.SATELLITE_NOT_SUPPORTED, null);
1789             return;
1790         }
1791 
1792         Boolean satelliteProvisioned = isSatelliteProvisioned();
1793         if (satelliteProvisioned == null) {
1794             result.send(SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE, null);
1795             return;
1796         }
1797         if (!satelliteProvisioned) {
1798             result.send(SatelliteManager.SATELLITE_SERVICE_NOT_PROVISIONED, null);
1799             return;
1800         }
1801 
1802         Phone phone = SatelliteServiceUtils.getPhone();
1803         sendRequestAsync(CMD_GET_TIME_SATELLITE_NEXT_VISIBLE, result, phone);
1804     }
1805 
1806     /**
1807      * Inform whether the device is aligned with satellite for demo mode.
1808      *
1809      * @param subId The subId of the subscription.
1810      * @param isAligned {@true} means device is aligned with the satellite, otherwise {@false}.
1811      */
onDeviceAlignedWithSatellite(@onNull int subId, @NonNull boolean isAligned)1812     public void onDeviceAlignedWithSatellite(@NonNull int subId, @NonNull boolean isAligned) {
1813         mDatagramController.onDeviceAlignedWithSatellite(isAligned);
1814     }
1815 
1816     /**
1817      * This API can be used by only CTS to update satellite vendor service package name.
1818      *
1819      * @param servicePackageName The package name of the satellite vendor service.
1820      * @return {@code true} if the satellite vendor service is set successfully,
1821      * {@code false} otherwise.
1822      */
setSatelliteServicePackageName(@ullable String servicePackageName)1823     public boolean setSatelliteServicePackageName(@Nullable String servicePackageName) {
1824         if (!isMockModemAllowed()) return false;
1825 
1826         // Cached states need to be cleared whenever switching satellite vendor services.
1827         logd("setSatelliteServicePackageName: Resetting cached states");
1828         synchronized (mIsSatelliteSupportedLock) {
1829             mIsSatelliteSupported = null;
1830         }
1831         synchronized (mIsSatelliteProvisionedLock) {
1832             mIsSatelliteProvisioned = null;
1833         }
1834         synchronized (mIsSatelliteEnabledLock) {
1835             mIsSatelliteEnabled = null;
1836         }
1837         synchronized (mSatelliteCapabilitiesLock) {
1838             mSatelliteCapabilities = null;
1839         }
1840         mSatelliteModemInterface.setSatelliteServicePackageName(servicePackageName);
1841         return true;
1842     }
1843 
1844     /**
1845      * This API can be used by only CTS to update the timeout duration in milliseconds that
1846      * satellite should stay at listening mode to wait for the next incoming page before disabling
1847      * listening mode.
1848      *
1849      * @param timeoutMillis The timeout duration in millisecond.
1850      * @return {@code true} if the timeout duration is set successfully, {@code false} otherwise.
1851      */
setSatelliteListeningTimeoutDuration(long timeoutMillis)1852     public boolean setSatelliteListeningTimeoutDuration(long timeoutMillis) {
1853         if (mSatelliteSessionController == null) {
1854             loge("mSatelliteSessionController is not initialized yet");
1855             return false;
1856         }
1857         return mSatelliteSessionController.setSatelliteListeningTimeoutDuration(timeoutMillis);
1858     }
1859 
1860     /**
1861      * This API can be used by only CTS to update the timeout duration in milliseconds whether
1862      * the device is aligned with the satellite for demo mode
1863      *
1864      * @param timeoutMillis The timeout duration in millisecond.
1865      * @return {@code true} if the timeout duration is set successfully, {@code false} otherwise.
1866      */
setSatelliteDeviceAlignedTimeoutDuration(long timeoutMillis)1867     public boolean setSatelliteDeviceAlignedTimeoutDuration(long timeoutMillis) {
1868         return mDatagramController.setSatelliteDeviceAlignedTimeoutDuration(timeoutMillis);
1869     }
1870 
1871     /**
1872      * This API can be used by only CTS to update satellite gateway service package name.
1873      *
1874      * @param servicePackageName The package name of the satellite gateway service.
1875      * @return {@code true} if the satellite gateway service is set successfully,
1876      * {@code false} otherwise.
1877      */
setSatelliteGatewayServicePackageName(@ullable String servicePackageName)1878     public boolean setSatelliteGatewayServicePackageName(@Nullable String servicePackageName) {
1879         if (mSatelliteSessionController == null) {
1880             loge("mSatelliteSessionController is not initialized yet");
1881             return false;
1882         }
1883         return mSatelliteSessionController.setSatelliteGatewayServicePackageName(
1884                 servicePackageName);
1885     }
1886 
1887     /**
1888      * This API can be used by only CTS to update satellite pointing UI app package and class names.
1889      *
1890      * @param packageName The package name of the satellite pointing UI app.
1891      * @param className The class name of the satellite pointing UI app.
1892      * @return {@code true} if the satellite pointing UI app package and class is set successfully,
1893      * {@code false} otherwise.
1894      */
setSatellitePointingUiClassName( @ullable String packageName, @Nullable String className)1895     public boolean setSatellitePointingUiClassName(
1896             @Nullable String packageName, @Nullable String className) {
1897         return mPointingAppController.setSatellitePointingUiClassName(packageName, className);
1898     }
1899 
1900     /**
1901      * This function is used by {@link SatelliteModemInterface} to notify
1902      * {@link SatelliteController} that the satellite vendor service was just connected.
1903      * <p>
1904      * {@link SatelliteController} will send requests to satellite modem to check whether it support
1905      * satellite and whether it is provisioned. {@link SatelliteController} will use these cached
1906      * values to serve requests from its clients.
1907      * <p>
1908      * Because satellite vendor service might have just come back from a crash, we need to disable
1909      * the satellite modem so that resources will be cleaned up and internal states will be reset.
1910      */
1911     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
onSatelliteServiceConnected()1912     public void onSatelliteServiceConnected() {
1913         if (mSatelliteModemInterface.isSatelliteServiceSupported()) {
1914             synchronized (mIsSatelliteSupportedLock) {
1915                 if (mIsSatelliteSupported == null) {
1916                     ResultReceiver receiver = new ResultReceiver(this) {
1917                         @Override
1918                         protected void onReceiveResult(
1919                                 int resultCode, Bundle resultData) {
1920                             logd("requestIsSatelliteSupported: resultCode="
1921                                     + resultCode);
1922                         }
1923                     };
1924                     requestIsSatelliteSupported(
1925                             SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, receiver);
1926                 }
1927             }
1928         } else {
1929             logd("onSatelliteServiceConnected: Satellite vendor service is not supported."
1930                     + " Ignored the event");
1931         }
1932     }
1933 
1934     /**
1935      * @return {@code true} is satellite is supported on the device, {@code  false} otherwise.
1936      */
isSatelliteSupported()1937     public boolean isSatelliteSupported() {
1938         Boolean supported = isSatelliteSupportedInternal();
1939         return (supported != null ? supported : false);
1940     }
1941 
1942     /**
1943      * @return The list of satellite PLMNs used for connecting to satellite networks.
1944      */
1945     @NonNull
getSatellitePlmnList()1946     public List<String> getSatellitePlmnList() {
1947         return new ArrayList<>(mSatellitePlmnList);
1948     }
1949 
1950     /**
1951      * @param subId Subscription ID.
1952      * @param plmn The satellite roaming plmn.
1953      * @return The list of services supported by the carrier associated with the {@code subId} for
1954      * the satellite network {@code plmn}.
1955      */
1956     @NonNull
getSupportedSatelliteServices(int subId, String plmn)1957     public List<Integer> getSupportedSatelliteServices(int subId, String plmn) {
1958         synchronized (mSupportedSatelliteServicesLock) {
1959             if (mSupportedSatelliteServices.containsKey(subId)) {
1960                 Map<String, Set<Integer>> supportedServices =
1961                         mSupportedSatelliteServices.get(subId);
1962                 if (supportedServices != null && supportedServices.containsKey(plmn)) {
1963                     return new ArrayList<>(supportedServices.get(plmn));
1964                 } else {
1965                     loge("getSupportedSatelliteServices: subId=" + subId + ", supportedServices "
1966                             + "does not contain key plmn=" + plmn);
1967                 }
1968             } else {
1969                 loge("getSupportedSatelliteServices: mSupportedSatelliteServices does contain key"
1970                         + " subId=" + subId);
1971             }
1972             return new ArrayList<>();
1973         }
1974     }
1975 
1976     /**
1977      * If we have not successfully queried the satellite modem for its satellite service support,
1978      * we will retry the query one more time. Otherwise, we will return the cached result.
1979      */
isSatelliteSupportedInternal()1980     private Boolean isSatelliteSupportedInternal() {
1981         synchronized (mIsSatelliteSupportedLock) {
1982             if (mIsSatelliteSupported != null) {
1983                 /* We have already successfully queried the satellite modem. */
1984                 return mIsSatelliteSupported;
1985             }
1986         }
1987         /**
1988          * We have not successfully checked whether the modem supports satellite service.
1989          * Thus, we need to retry it now.
1990          */
1991         requestIsSatelliteSupported(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID,
1992                 new ResultReceiver(this) {
1993                     @Override
1994                     protected void onReceiveResult(int resultCode, Bundle resultData) {
1995                         logd("requestIsSatelliteSupported: resultCode=" + resultCode);
1996                     }
1997                 });
1998         return null;
1999     }
2000 
handleEventProvisionSatelliteServiceDone( @onNull ProvisionSatelliteServiceArgument arg, @SatelliteManager.SatelliteError int result)2001     private void handleEventProvisionSatelliteServiceDone(
2002             @NonNull ProvisionSatelliteServiceArgument arg,
2003             @SatelliteManager.SatelliteError int result) {
2004         logd("handleEventProvisionSatelliteServiceDone: result="
2005                 + result + ", subId=" + arg.subId);
2006 
2007         Consumer<Integer> callback = mSatelliteProvisionCallbacks.remove(arg.subId);
2008         if (callback == null) {
2009             loge("handleEventProvisionSatelliteServiceDone: callback is null for subId="
2010                     + arg.subId);
2011             mProvisionMetricsStats
2012                     .setResultCode(SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE)
2013                     .setIsProvisionRequest(true)
2014                     .reportProvisionMetrics();
2015             mControllerMetricsStats.reportProvisionCount(
2016                     SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE);
2017             return;
2018         }
2019         callback.accept(result);
2020     }
2021 
handleEventDeprovisionSatelliteServiceDone( @onNull ProvisionSatelliteServiceArgument arg, @SatelliteManager.SatelliteError int result)2022     private void handleEventDeprovisionSatelliteServiceDone(
2023             @NonNull ProvisionSatelliteServiceArgument arg,
2024             @SatelliteManager.SatelliteError int result) {
2025         if (arg == null) {
2026             loge("handleEventDeprovisionSatelliteServiceDone: arg is null");
2027             return;
2028         }
2029         logd("handleEventDeprovisionSatelliteServiceDone: result="
2030                 + result + ", subId=" + arg.subId);
2031 
2032         if (arg.callback != null) {
2033             arg.callback.accept(result);
2034             mProvisionMetricsStats.setResultCode(result)
2035                     .setIsProvisionRequest(false)
2036                     .reportProvisionMetrics();
2037             mControllerMetricsStats.reportDeprovisionCount(result);
2038         }
2039     }
2040 
handleStartSatelliteTransmissionUpdatesDone(@onNull AsyncResult ar)2041     private void handleStartSatelliteTransmissionUpdatesDone(@NonNull AsyncResult ar) {
2042         SatelliteControllerHandlerRequest request = (SatelliteControllerHandlerRequest) ar.userObj;
2043         SatelliteTransmissionUpdateArgument arg =
2044                 (SatelliteTransmissionUpdateArgument) request.argument;
2045         int errorCode =  SatelliteServiceUtils.getSatelliteError(ar,
2046                 "handleStartSatelliteTransmissionUpdatesDone");
2047         arg.errorCallback.accept(errorCode);
2048 
2049         if (errorCode != SatelliteManager.SATELLITE_ERROR_NONE) {
2050             mPointingAppController.setStartedSatelliteTransmissionUpdates(false);
2051             // We need to remove the callback from our listener list since the caller might not call
2052             // stopSatelliteTransmissionUpdates to unregister the callback in case of failure.
2053             mPointingAppController.unregisterForSatelliteTransmissionUpdates(arg.subId,
2054                     arg.errorCallback, arg.callback, request.phone);
2055         } else {
2056             mPointingAppController.setStartedSatelliteTransmissionUpdates(true);
2057         }
2058     }
2059 
2060     /**
2061      * Posts the specified command to be executed on the main thread and returns immediately.
2062      *
2063      * @param command command to be executed on the main thread
2064      * @param argument additional parameters required to perform of the operation
2065      * @param phone phone object used to perform the operation.
2066      */
sendRequestAsync(int command, @NonNull Object argument, @Nullable Phone phone)2067     private void sendRequestAsync(int command, @NonNull Object argument, @Nullable Phone phone) {
2068         SatelliteControllerHandlerRequest request = new SatelliteControllerHandlerRequest(
2069                 argument, phone);
2070         Message msg = this.obtainMessage(command, request);
2071         msg.sendToTarget();
2072     }
2073 
2074     /**
2075      * Posts the specified command to be executed on the main thread. As this is a synchronous
2076      * request, it waits until the request is complete and then return the result.
2077      *
2078      * @param command command to be executed on the main thread
2079      * @param argument additional parameters required to perform of the operation
2080      * @param phone phone object used to perform the operation.
2081      * @return result of the operation
2082      */
sendRequest(int command, @NonNull Object argument, @Nullable Phone phone)2083     private @Nullable Object sendRequest(int command, @NonNull Object argument,
2084             @Nullable Phone phone) {
2085         if (Looper.myLooper() == this.getLooper()) {
2086             throw new RuntimeException("This method will deadlock if called from the main thread");
2087         }
2088 
2089         SatelliteControllerHandlerRequest request = new SatelliteControllerHandlerRequest(
2090                 argument, phone);
2091         Message msg = this.obtainMessage(command, request);
2092         msg.sendToTarget();
2093 
2094         synchronized (request) {
2095             while(request.result == null) {
2096                 try {
2097                     request.wait();
2098                 } catch (InterruptedException e) {
2099                     // Do nothing, go back and wait until the request is complete.
2100                 }
2101             }
2102         }
2103         return request.result;
2104     }
2105 
2106     /**
2107      * Check if satellite is provisioned for a subscription on the device.
2108      * @return true if satellite is provisioned on the given subscription else return false.
2109      */
2110     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
isSatelliteProvisioned()2111     protected Boolean isSatelliteProvisioned() {
2112         synchronized (mIsSatelliteProvisionedLock) {
2113             if (mIsSatelliteProvisioned != null) {
2114                 return mIsSatelliteProvisioned;
2115             }
2116         }
2117 
2118         requestIsSatelliteProvisioned(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID,
2119                 new ResultReceiver(this) {
2120                     @Override
2121                     protected void onReceiveResult(int resultCode, Bundle resultData) {
2122                         logd("requestIsSatelliteProvisioned: resultCode=" + resultCode);
2123                     }
2124                 });
2125         return null;
2126     }
2127 
handleSatelliteEnabled(SatelliteControllerHandlerRequest request)2128     private void handleSatelliteEnabled(SatelliteControllerHandlerRequest request) {
2129         RequestSatelliteEnabledArgument argument =
2130                 (RequestSatelliteEnabledArgument) request.argument;
2131         Phone phone = request.phone;
2132 
2133         if (!argument.enableSatellite && (mSatelliteModemInterface.isSatelliteServiceSupported()
2134                 || phone != null)) {
2135             synchronized (mIsSatelliteEnabledLock) {
2136                 mWaitingForDisableSatelliteModemResponse = true;
2137                 mWaitingForSatelliteModemOff = true;
2138             }
2139         }
2140 
2141         Message onCompleted = obtainMessage(EVENT_SET_SATELLITE_ENABLED_DONE, request);
2142         if (mSatelliteModemInterface.isSatelliteServiceSupported()) {
2143             mSatelliteModemInterface.requestSatelliteEnabled(argument.enableSatellite,
2144                     argument.enableDemoMode, onCompleted);
2145             return;
2146         }
2147 
2148         if (phone != null) {
2149             phone.setSatellitePower(onCompleted, argument.enableSatellite);
2150         } else {
2151             loge("requestSatelliteEnabled: No phone object");
2152             argument.callback.accept(SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE);
2153         }
2154     }
2155 
updateSatelliteSupportedStateWhenSatelliteServiceConnected(boolean supported)2156     private void updateSatelliteSupportedStateWhenSatelliteServiceConnected(boolean supported) {
2157         synchronized (mIsSatelliteSupportedLock) {
2158             mIsSatelliteSupported = supported;
2159         }
2160         mSatelliteSessionController = SatelliteSessionController.make(
2161                 mContext, getLooper(), supported);
2162         if (supported) {
2163             registerForSatelliteProvisionStateChanged();
2164             registerForPendingDatagramCount();
2165             registerForSatelliteModemStateChanged();
2166 
2167             requestIsSatelliteProvisioned(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID,
2168                     new ResultReceiver(this) {
2169                         @Override
2170                         protected void onReceiveResult(int resultCode, Bundle resultData) {
2171                             logd("requestIsSatelliteProvisioned: resultCode=" + resultCode);
2172                             requestSatelliteEnabled(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID,
2173                                     false, false,
2174                                     new IIntegerConsumer.Stub() {
2175                                         @Override
2176                                         public void accept(int result) {
2177                                             logd("requestSatelliteEnabled: result=" + result);
2178                                         }
2179                                     });
2180                         }
2181                     });
2182             requestSatelliteCapabilities(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID,
2183                     new ResultReceiver(this) {
2184                         @Override
2185                         protected void onReceiveResult(int resultCode, Bundle resultData) {
2186                             logd("requestSatelliteCapabilities: resultCode=" + resultCode);
2187                         }
2188                     });
2189         }
2190     }
2191 
updateSatelliteEnabledState(boolean enabled, String caller)2192     private void updateSatelliteEnabledState(boolean enabled, String caller) {
2193         synchronized (mIsSatelliteEnabledLock) {
2194             mIsSatelliteEnabled = enabled;
2195         }
2196         if (mSatelliteSessionController != null) {
2197             mSatelliteSessionController.onSatelliteEnabledStateChanged(enabled);
2198             mSatelliteSessionController.setDemoMode(mIsDemoModeEnabled);
2199         } else {
2200             loge(caller + ": mSatelliteSessionController is not initialized yet");
2201         }
2202     }
2203 
registerForSatelliteProvisionStateChanged()2204     private void registerForSatelliteProvisionStateChanged() {
2205         if (mSatelliteModemInterface.isSatelliteServiceSupported()) {
2206             if (!mRegisteredForProvisionStateChangedWithSatelliteService.get()) {
2207                 mSatelliteModemInterface.registerForSatelliteProvisionStateChanged(
2208                         this, EVENT_SATELLITE_PROVISION_STATE_CHANGED, null);
2209                 mRegisteredForProvisionStateChangedWithSatelliteService.set(true);
2210             }
2211         } else {
2212             Phone phone = SatelliteServiceUtils.getPhone();
2213             if (phone == null) {
2214                 loge("registerForSatelliteProvisionStateChanged: phone is null");
2215             } else if (!mRegisteredForProvisionStateChangedWithPhone.get()) {
2216                 phone.registerForSatelliteProvisionStateChanged(
2217                         this, EVENT_SATELLITE_PROVISION_STATE_CHANGED, null);
2218                 mRegisteredForProvisionStateChangedWithPhone.set(true);
2219             }
2220         }
2221     }
2222 
registerForPendingDatagramCount()2223     private void registerForPendingDatagramCount() {
2224         if (mSatelliteModemInterface.isSatelliteServiceSupported()) {
2225             if (!mRegisteredForPendingDatagramCountWithSatelliteService.get()) {
2226                 mSatelliteModemInterface.registerForPendingDatagrams(
2227                         this, EVENT_PENDING_DATAGRAMS, null);
2228                 mRegisteredForPendingDatagramCountWithSatelliteService.set(true);
2229             }
2230         } else {
2231             Phone phone = SatelliteServiceUtils.getPhone();
2232             if (phone == null) {
2233                 loge("registerForPendingDatagramCount: satellite phone is "
2234                         + "not initialized yet");
2235             } else if (!mRegisteredForPendingDatagramCountWithPhone.get()) {
2236                 phone.registerForPendingDatagramCount(this, EVENT_PENDING_DATAGRAMS, null);
2237                 mRegisteredForPendingDatagramCountWithPhone.set(true);
2238             }
2239         }
2240     }
2241 
registerForSatelliteModemStateChanged()2242     private void registerForSatelliteModemStateChanged() {
2243         if (mSatelliteModemInterface.isSatelliteServiceSupported()) {
2244             if (!mRegisteredForSatelliteModemStateChangedWithSatelliteService.get()) {
2245                 mSatelliteModemInterface.registerForSatelliteModemStateChanged(
2246                         this, EVENT_SATELLITE_MODEM_STATE_CHANGED, null);
2247                 mRegisteredForSatelliteModemStateChangedWithSatelliteService.set(true);
2248             }
2249         } else {
2250             Phone phone = SatelliteServiceUtils.getPhone();
2251             if (phone == null) {
2252                 loge("registerForSatelliteModemStateChanged: satellite phone is "
2253                         + "not initialized yet");
2254             } else if (!mRegisteredForSatelliteModemStateChangedWithPhone.get()) {
2255                 phone.registerForSatelliteModemStateChanged(
2256                         this, EVENT_SATELLITE_MODEM_STATE_CHANGED, null);
2257                 mRegisteredForSatelliteModemStateChangedWithPhone.set(true);
2258             }
2259         }
2260     }
2261 
handleEventSatelliteProvisionStateChanged(boolean provisioned)2262     private void handleEventSatelliteProvisionStateChanged(boolean provisioned) {
2263         logd("handleSatelliteProvisionStateChangedEvent: provisioned=" + provisioned);
2264 
2265         synchronized (mIsSatelliteProvisionedLock) {
2266             mIsSatelliteProvisioned = provisioned;
2267         }
2268 
2269         List<ISatelliteProvisionStateCallback> toBeRemoved = new ArrayList<>();
2270         mSatelliteProvisionStateChangedListeners.values().forEach(listener -> {
2271             try {
2272                 listener.onSatelliteProvisionStateChanged(provisioned);
2273             } catch (RemoteException e) {
2274                 logd("handleSatelliteProvisionStateChangedEvent RemoteException: " + e);
2275                 toBeRemoved.add(listener);
2276             }
2277         });
2278         toBeRemoved.forEach(listener -> {
2279             mSatelliteProvisionStateChangedListeners.remove(listener.asBinder());
2280         });
2281     }
2282 
handleEventSatelliteModemStateChanged( @atelliteManager.SatelliteModemState int state)2283     private void handleEventSatelliteModemStateChanged(
2284             @SatelliteManager.SatelliteModemState int state) {
2285         logd("handleEventSatelliteModemStateChanged: state=" + state);
2286         if (state == SatelliteManager.SATELLITE_MODEM_STATE_UNAVAILABLE
2287                 || state == SatelliteManager.SATELLITE_MODEM_STATE_OFF) {
2288             synchronized (mIsSatelliteEnabledLock) {
2289                 if ((state == SatelliteManager.SATELLITE_MODEM_STATE_UNAVAILABLE)
2290                         || ((mIsSatelliteEnabled == null || isSatelliteEnabled())
2291                         && !mWaitingForDisableSatelliteModemResponse)) {
2292                     int error = (state == SatelliteManager.SATELLITE_MODEM_STATE_OFF)
2293                             ? SatelliteManager.SATELLITE_ERROR_NONE
2294                             : SatelliteManager.SATELLITE_INVALID_MODEM_STATE;
2295                     Consumer<Integer> callback = null;
2296                     synchronized (mSatelliteEnabledRequestLock) {
2297                         if (mSatelliteEnabledRequest != null) {
2298                             callback = mSatelliteEnabledRequest.callback;
2299                         }
2300                     }
2301                     moveSatelliteToOffStateAndCleanUpResources(error, callback);
2302                 } else {
2303                     logd("Either waiting for the response of disabling satellite modem or the event"
2304                             + " should be ignored because isSatelliteEnabled="
2305                             + isSatelliteEnabled()
2306                             + ", mIsSatelliteEnabled=" + mIsSatelliteEnabled);
2307                 }
2308                 mWaitingForSatelliteModemOff = false;
2309             }
2310         }
2311         mDatagramController.onSatelliteModemStateChanged(state);
2312     }
2313 
2314     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
setSettingsKeyForSatelliteMode(int val)2315     protected void setSettingsKeyForSatelliteMode(int val) {
2316         logd("setSettingsKeyForSatelliteMode val: " + val);
2317         Settings.Global.putInt(mContext.getContentResolver(),
2318                     Settings.Global.SATELLITE_MODE_ENABLED, val);
2319     }
2320 
2321     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
areAllRadiosDisabled()2322     protected boolean areAllRadiosDisabled() {
2323         synchronized (mRadioStateLock) {
2324             if ((mDisableBTOnSatelliteEnabled && mBTStateEnabled)
2325                     || (mDisableNFCOnSatelliteEnabled && mNfcStateEnabled)
2326                     || (mDisableWifiOnSatelliteEnabled && mWifiStateEnabled)
2327                     || (mDisableUWBOnSatelliteEnabled && mUwbStateEnabled)) {
2328                 logd("All radios are not disabled yet.");
2329                 return false;
2330             }
2331             logd("All radios are disabled.");
2332             return true;
2333         }
2334     }
2335 
evaluateToSendSatelliteEnabledSuccess()2336     private void evaluateToSendSatelliteEnabledSuccess() {
2337         logd("evaluateToSendSatelliteEnabledSuccess");
2338         synchronized (mSatelliteEnabledRequestLock) {
2339             if (areAllRadiosDisabled() && (mSatelliteEnabledRequest != null)
2340                     && mWaitingForRadioDisabled) {
2341                 logd("Sending success to callback that sent enable satellite request");
2342                 setDemoModeEnabled(mSatelliteEnabledRequest.enableDemoMode);
2343                 synchronized (mIsSatelliteEnabledLock) {
2344                     mIsSatelliteEnabled = mSatelliteEnabledRequest.enableSatellite;
2345                 }
2346                 mSatelliteEnabledRequest.callback.accept(SatelliteManager.SATELLITE_ERROR_NONE);
2347                 updateSatelliteEnabledState(
2348                         mSatelliteEnabledRequest.enableSatellite,
2349                         "EVENT_SET_SATELLITE_ENABLED_DONE");
2350                 mSatelliteEnabledRequest = null;
2351                 mWaitingForRadioDisabled = false;
2352             }
2353         }
2354     }
2355 
resetSatelliteEnabledRequest()2356     private void resetSatelliteEnabledRequest() {
2357         logd("resetSatelliteEnabledRequest");
2358         synchronized (mSatelliteEnabledRequestLock) {
2359             mSatelliteEnabledRequest = null;
2360             mWaitingForRadioDisabled = false;
2361         }
2362     }
2363 
moveSatelliteToOffStateAndCleanUpResources( @atelliteManager.SatelliteError int error, @Nullable Consumer<Integer> callback)2364     private void moveSatelliteToOffStateAndCleanUpResources(
2365             @SatelliteManager.SatelliteError int error, @Nullable Consumer<Integer> callback) {
2366         logd("moveSatelliteToOffStateAndCleanUpResources");
2367         synchronized (mIsSatelliteEnabledLock) {
2368             resetSatelliteEnabledRequest();
2369             setDemoModeEnabled(false);
2370             mIsSatelliteEnabled = false;
2371             setSettingsKeyForSatelliteMode(SATELLITE_MODE_ENABLED_FALSE);
2372             if (callback != null) callback.accept(error);
2373             updateSatelliteEnabledState(
2374                     false, "moveSatelliteToOffStateAndCleanUpResources");
2375         }
2376     }
2377 
setDemoModeEnabled(boolean enabled)2378     private void setDemoModeEnabled(boolean enabled) {
2379         mIsDemoModeEnabled = enabled;
2380         mDatagramController.setDemoMode(mIsDemoModeEnabled);
2381     }
2382 
isMockModemAllowed()2383     private boolean isMockModemAllowed() {
2384         return (DEBUG || SystemProperties.getBoolean(ALLOW_MOCK_MODEM_PROPERTY, false));
2385     }
2386 
updateSupportedSatelliteServicesForActiveSubscriptions()2387     private void updateSupportedSatelliteServicesForActiveSubscriptions() {
2388         synchronized (mSupportedSatelliteServicesLock) {
2389             mSupportedSatelliteServices.clear();
2390             int[] activeSubIds = SubscriptionManagerService.getInstance().getActiveSubIdList(true);
2391             if (activeSubIds != null) {
2392                 for (int subId : activeSubIds) {
2393                     updateSupportedSatelliteServices(subId);
2394                 }
2395             } else {
2396                 loge("updateSupportedSatelliteServicesForActiveSubscriptions: "
2397                         + "activeSubIds is null");
2398             }
2399         }
2400     }
2401 
updateSupportedSatelliteServices(int subId)2402     private void updateSupportedSatelliteServices(int subId) {
2403         Map<String, Set<Integer>> carrierSupportedSatelliteServicesPerPlmn =
2404                 readSupportedSatelliteServicesFromCarrierConfig(subId);
2405         synchronized (mSupportedSatelliteServicesLock) {
2406             mSupportedSatelliteServices.put(subId,
2407                     SatelliteServiceUtils.mergeSupportedSatelliteServices(
2408                             mSatelliteServicesSupportedByProviders,
2409                             carrierSupportedSatelliteServicesPerPlmn));
2410         }
2411     }
2412 
2413     @NonNull
readSupportedSatelliteServicesFromOverlayConfig()2414     private Map<String, Set<Integer>> readSupportedSatelliteServicesFromOverlayConfig() {
2415         String[] supportedServices = readStringArrayFromOverlayConfig(
2416                 R.array.config_satellite_services_supported_by_providers);
2417         return SatelliteServiceUtils.parseSupportedSatelliteServices(supportedServices);
2418     }
2419 
2420     @NonNull
readSupportedSatelliteServicesFromCarrierConfig(int subId)2421     private Map<String, Set<Integer>> readSupportedSatelliteServicesFromCarrierConfig(int subId) {
2422         synchronized (mCarrierConfigArrayLock) {
2423             PersistableBundle config = mCarrierConfigArray.get(subId);
2424             if (config == null) {
2425                 config = getConfigForSubId(subId);
2426                 mCarrierConfigArray.put(subId, config);
2427             }
2428             return SatelliteServiceUtils.parseSupportedSatelliteServices(
2429                     config.getPersistableBundle(CarrierConfigManager
2430                             .KEY_CARRIER_SUPPORTED_SATELLITE_SERVICES_PER_PROVIDER_BUNDLE));
2431         }
2432     }
2433 
getConfigForSubId(int subId)2434     @NonNull private PersistableBundle getConfigForSubId(int subId) {
2435         PersistableBundle config = mCarrierConfigManager.getConfigForSubId(subId,
2436                 CarrierConfigManager
2437                         .KEY_CARRIER_SUPPORTED_SATELLITE_SERVICES_PER_PROVIDER_BUNDLE);
2438         if (config == null || config.isEmpty()) {
2439             config = CarrierConfigManager.getDefaultConfig();
2440         }
2441         return config;
2442     }
2443 
handleCarrierConfigChanged(int slotIndex, int subId, int carrierId, int specificCarrierId)2444     private void handleCarrierConfigChanged(int slotIndex, int subId, int carrierId,
2445             int specificCarrierId) {
2446         logd("handleCarrierConfigChanged(): slotIndex(" + slotIndex + "), subId("
2447                 + subId + "), carrierId(" + carrierId + "), specificCarrierId("
2448                 + specificCarrierId + ")");
2449         if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
2450             return;
2451         }
2452 
2453         updateCarrierConfig(subId);
2454         updateSupportedSatelliteServicesForActiveSubscriptions();
2455     }
2456 
updateCarrierConfig(int subId)2457     private void updateCarrierConfig(int subId) {
2458         synchronized (mCarrierConfigArrayLock) {
2459             mCarrierConfigArray.put(subId, getConfigForSubId(subId));
2460         }
2461     }
2462 
2463     @NonNull
readStringArrayFromOverlayConfig(@rrayRes int id)2464     private String[] readStringArrayFromOverlayConfig(@ArrayRes int id) {
2465         String[] strArray = null;
2466         try {
2467             strArray = mContext.getResources().getStringArray(id);
2468         } catch (Resources.NotFoundException ex) {
2469             loge("readStringArrayFromOverlayConfig: id= " + id + ", ex=" + ex);
2470         }
2471         if (strArray == null) {
2472             strArray = new String[0];
2473         }
2474         return strArray;
2475     }
2476 
logd(@onNull String log)2477     private static void logd(@NonNull String log) {
2478         Rlog.d(TAG, log);
2479     }
2480 
loge(@onNull String log)2481     private static void loge(@NonNull String log) {
2482         Rlog.e(TAG, log);
2483     }
2484 }
2485