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.NonNull;
20 import android.annotation.Nullable;
21 import android.content.ComponentName;
22 import android.content.Context;
23 import android.content.Intent;
24 import android.content.ServiceConnection;
25 import android.os.AsyncResult;
26 import android.os.Binder;
27 import android.os.Handler;
28 import android.os.IBinder;
29 import android.os.Looper;
30 import android.os.Message;
31 import android.os.RegistrantList;
32 import android.os.RemoteException;
33 import android.telephony.DropBoxManagerLoggerBackend;
34 import android.telephony.IBooleanConsumer;
35 import android.telephony.IIntegerConsumer;
36 import android.telephony.PersistentLogger;
37 import android.telephony.Rlog;
38 import android.telephony.satellite.NtnSignalStrength;
39 import android.telephony.satellite.SatelliteCapabilities;
40 import android.telephony.satellite.SatelliteDatagram;
41 import android.telephony.satellite.SatelliteManager;
42 import android.telephony.satellite.SatelliteManager.SatelliteException;
43 import android.telephony.satellite.stub.INtnSignalStrengthConsumer;
44 import android.telephony.satellite.stub.ISatellite;
45 import android.telephony.satellite.stub.ISatelliteCapabilitiesConsumer;
46 import android.telephony.satellite.stub.ISatelliteListener;
47 import android.telephony.satellite.stub.SatelliteModemState;
48 import android.telephony.satellite.stub.SatelliteService;
49 import android.text.TextUtils;
50 import android.util.Pair;
51 
52 import com.android.internal.R;
53 import com.android.internal.annotations.VisibleForTesting;
54 import com.android.internal.telephony.ExponentialBackoff;
55 import com.android.internal.telephony.flags.FeatureFlags;
56 
57 import java.util.Arrays;
58 import java.util.List;
59 
60 /**
61  * Satellite modem interface to manage connections with the satellite service and HAL interface.
62  */
63 public class SatelliteModemInterface {
64     private static final String TAG = "SatelliteModemInterface";
65     private static final long REBIND_INITIAL_DELAY = 2 * 1000; // 2 seconds
66     private static final long REBIND_MAXIMUM_DELAY = 64 * 1000; // 1 minute
67     private static final int REBIND_MULTIPLIER = 2;
68 
69     @NonNull private static SatelliteModemInterface sInstance;
70     @NonNull private final Context mContext;
71     @NonNull private final DemoSimulator mDemoSimulator;
72     @NonNull private final SatelliteListener mVendorListener;
73     @NonNull private final SatelliteListener mDemoListener;
74     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
75     @NonNull protected final ExponentialBackoff mExponentialBackoff;
76     @NonNull private final Object mLock = new Object();
77     @NonNull private final SatelliteController mSatelliteController;
78     /**
79      * {@code true} to use the vendor satellite service and {@code false} to use the HAL.
80      */
81     private boolean mIsSatelliteServiceSupported;
82     @Nullable private ISatellite mSatelliteService;
83     @Nullable private SatelliteServiceConnection mSatelliteServiceConnection;
84     @NonNull private String mVendorSatellitePackageName = "";
85     private boolean mIsBound;
86     private boolean mIsBinding;
87     @Nullable private PersistentLogger mPersistentLogger = null;
88 
89     @NonNull private final RegistrantList mSatelliteProvisionStateChangedRegistrants =
90             new RegistrantList();
91     @NonNull private final RegistrantList mSatellitePositionInfoChangedRegistrants =
92             new RegistrantList();
93     @NonNull private final RegistrantList mDatagramTransferStateChangedRegistrants =
94             new RegistrantList();
95     @NonNull private final RegistrantList mSatelliteModemStateChangedRegistrants =
96             new RegistrantList();
97     @NonNull private final RegistrantList mPendingDatagramsRegistrants = new RegistrantList();
98     @NonNull private final RegistrantList mSatelliteDatagramsReceivedRegistrants =
99             new RegistrantList();
100     @NonNull private final RegistrantList mNtnSignalStrengthChangedRegistrants =
101             new RegistrantList();
102     @NonNull private final RegistrantList mSatelliteCapabilitiesChangedRegistrants =
103             new RegistrantList();
104     @NonNull private final RegistrantList mSatelliteSupportedStateChangedRegistrants =
105             new RegistrantList();
106 
107     private class SatelliteListener extends ISatelliteListener.Stub {
108 
109         private final boolean mIsDemoListener;
110 
SatelliteListener(boolean isDemoListener)111         SatelliteListener(boolean isDemoListener) {
112             mIsDemoListener = isDemoListener;
113         }
114 
115         @Override
onSatelliteProvisionStateChanged(boolean provisioned)116         public void onSatelliteProvisionStateChanged(boolean provisioned) {
117             mSatelliteProvisionStateChangedRegistrants.notifyResult(provisioned);
118         }
119 
120         @Override
onSatelliteDatagramReceived( android.telephony.satellite.stub.SatelliteDatagram datagram, int pendingCount)121         public void onSatelliteDatagramReceived(
122                 android.telephony.satellite.stub.SatelliteDatagram datagram, int pendingCount) {
123             if (notifyResultIfExpectedListener()) {
124                 plogd("onSatelliteDatagramReceived: pendingCount=" + pendingCount);
125                 mSatelliteDatagramsReceivedRegistrants.notifyResult(new Pair<>(
126                         SatelliteServiceUtils.fromSatelliteDatagram(datagram), pendingCount));
127             }
128         }
129 
130         @Override
onPendingDatagrams()131         public void onPendingDatagrams() {
132             if (notifyResultIfExpectedListener()) {
133                 plogd("onPendingDatagrams");
134                 mPendingDatagramsRegistrants.notifyResult(null);
135             }
136         }
137 
138         @Override
onSatellitePositionChanged( android.telephony.satellite.stub.PointingInfo pointingInfo)139         public void onSatellitePositionChanged(
140                 android.telephony.satellite.stub.PointingInfo pointingInfo) {
141             mSatellitePositionInfoChangedRegistrants.notifyResult(
142                     SatelliteServiceUtils.fromPointingInfo(pointingInfo));
143         }
144 
145         @Override
onSatelliteModemStateChanged(int state)146         public void onSatelliteModemStateChanged(int state) {
147             if (notifyModemStateChanged(state)) {
148                 mSatelliteModemStateChangedRegistrants.notifyResult(
149                         SatelliteServiceUtils.fromSatelliteModemState(state));
150                 int datagramTransferState =
151                         SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_UNKNOWN;
152                 switch (state) {
153                     case SatelliteManager.SATELLITE_MODEM_STATE_IDLE:
154                         datagramTransferState =
155                                 SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE;
156                         break;
157                     case SatelliteManager.SATELLITE_MODEM_STATE_LISTENING:
158                         datagramTransferState =
159                                 SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVING;
160                         break;
161                     case SatelliteManager.SATELLITE_MODEM_STATE_DATAGRAM_TRANSFERRING:
162                         datagramTransferState =
163                                 SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_SENDING;
164                         break;
165                     case SatelliteManager.SATELLITE_MODEM_STATE_DATAGRAM_RETRYING:
166                         // keep previous state as this could be retrying sending or receiving
167                         break;
168                 }
169                 mDatagramTransferStateChangedRegistrants.notifyResult(datagramTransferState);
170             }
171         }
172 
173         @Override
onNtnSignalStrengthChanged( android.telephony.satellite.stub.NtnSignalStrength ntnSignalStrength)174         public void onNtnSignalStrengthChanged(
175                 android.telephony.satellite.stub.NtnSignalStrength ntnSignalStrength) {
176             if (notifyResultIfExpectedListener()) {
177                 mNtnSignalStrengthChangedRegistrants.notifyResult(
178                         SatelliteServiceUtils.fromNtnSignalStrength(ntnSignalStrength));
179             }
180         }
181 
182         @Override
onSatelliteCapabilitiesChanged( android.telephony.satellite.stub.SatelliteCapabilities satelliteCapabilities)183         public void onSatelliteCapabilitiesChanged(
184                 android.telephony.satellite.stub.SatelliteCapabilities satelliteCapabilities) {
185             mSatelliteCapabilitiesChangedRegistrants.notifyResult(
186                     SatelliteServiceUtils.fromSatelliteCapabilities(satelliteCapabilities));
187         }
188 
189         @Override
onSatelliteSupportedStateChanged(boolean supported)190         public void onSatelliteSupportedStateChanged(boolean supported) {
191             mSatelliteSupportedStateChangedRegistrants.notifyResult(supported);
192         }
193 
194         @Override
onRegistrationFailure(int causeCode)195         public void onRegistrationFailure(int causeCode) {
196             // TO-DO notify registrants
197         }
198 
notifyResultIfExpectedListener()199         private boolean notifyResultIfExpectedListener() {
200             // Demo listener should notify results only during demo mode
201             // Vendor listener should notify result only during real mode
202             return mIsDemoListener == mSatelliteController.isDemoModeEnabled();
203         }
204 
notifyModemStateChanged(int state)205         private boolean notifyModemStateChanged(int state) {
206             if (notifyResultIfExpectedListener()) {
207                 return true;
208             }
209 
210             return state == SatelliteModemState.SATELLITE_MODEM_STATE_OFF
211                     || state == SatelliteModemState.SATELLITE_MODEM_STATE_UNAVAILABLE;
212         }
213     }
214 
215     /**
216      * @return The singleton instance of SatelliteModemInterface.
217      */
getInstance()218     public static SatelliteModemInterface getInstance() {
219         if (sInstance == null) {
220             loge("SatelliteModemInterface was not yet initialized.");
221         }
222         return sInstance;
223     }
224 
225     /**
226      * Create the SatelliteModemInterface singleton instance.
227      * @param context The Context to use to create the SatelliteModemInterface.
228      * @param satelliteController The singleton instance of SatelliteController.
229      * @param featureFlags The telephony feature flags.
230      * @return The singleton instance of SatelliteModemInterface.
231      */
make(@onNull Context context, SatelliteController satelliteController, @NonNull FeatureFlags featureFlags)232     public static SatelliteModemInterface make(@NonNull Context context,
233             SatelliteController satelliteController,
234             @NonNull FeatureFlags featureFlags) {
235         if (sInstance == null) {
236             sInstance = new SatelliteModemInterface(
237                     context, satelliteController, Looper.getMainLooper(), featureFlags);
238         }
239         return sInstance;
240     }
241 
242     /**
243      * Create a SatelliteModemInterface to manage connections to the SatelliteService.
244      *
245      * @param context The Context for the SatelliteModemInterface.
246      * @param featureFlags The telephony feature flags.
247      * @param looper The Looper to run binding retry on.
248      */
249     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
SatelliteModemInterface(@onNull Context context, SatelliteController satelliteController, @NonNull Looper looper, @NonNull FeatureFlags featureFlags)250     protected SatelliteModemInterface(@NonNull Context context,
251             SatelliteController satelliteController,
252             @NonNull Looper looper,
253             @NonNull FeatureFlags featureFlags) {
254         if (isSatellitePersistentLoggingEnabled(context, featureFlags)) {
255             mPersistentLogger = new PersistentLogger(
256                     DropBoxManagerLoggerBackend.getInstance(context));
257         }
258         mContext = context;
259         mDemoSimulator = DemoSimulator.make(context, satelliteController);
260         mVendorListener = new SatelliteListener(false);
261         mDemoListener = new SatelliteListener(true);
262         mIsSatelliteServiceSupported = getSatelliteServiceSupport();
263         mSatelliteController = satelliteController;
264         mExponentialBackoff = new ExponentialBackoff(REBIND_INITIAL_DELAY, REBIND_MAXIMUM_DELAY,
265                 REBIND_MULTIPLIER, looper, () -> {
266             synchronized (mLock) {
267                 if ((mIsBound && mSatelliteService != null) || mIsBinding) {
268                     return;
269                 }
270             }
271             if (mSatelliteServiceConnection != null) {
272                 synchronized (mLock) {
273                     mIsBound = false;
274                     mIsBinding = false;
275                 }
276                 unbindService();
277             }
278             bindService();
279         });
280         mExponentialBackoff.start();
281         plogd("Created SatelliteModemInterface. Attempting to bind to SatelliteService.");
282         bindService();
283     }
284 
285     /**
286      * Get the SatelliteService interface, if it exists.
287      *
288      * @return The bound ISatellite, or {@code null} if it is not yet connected.
289      */
getService()290     @Nullable public ISatellite getService() {
291         return mSatelliteService;
292     }
293 
getSatellitePackageName()294     @NonNull private String getSatellitePackageName() {
295         if (!TextUtils.isEmpty(mVendorSatellitePackageName)) {
296             return mVendorSatellitePackageName;
297         }
298         return TextUtils.emptyIfNull(mContext.getResources().getString(
299                 R.string.config_satellite_service_package));
300     }
301 
getSatelliteServiceSupport()302     private boolean getSatelliteServiceSupport() {
303         return !TextUtils.isEmpty(getSatellitePackageName());
304     }
305 
306     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
bindService()307     protected void bindService() {
308         synchronized (mLock) {
309             if (mIsBinding || mIsBound) return;
310             mIsBinding = true;
311         }
312         String packageName = getSatellitePackageName();
313         if (TextUtils.isEmpty(packageName)) {
314             ploge("Unable to bind to the satellite service because the package is undefined.");
315             // Since the package name comes from static device configs, stop retry because
316             // rebind will continue to fail without a valid package name.
317             synchronized (mLock) {
318                 mIsBinding = false;
319             }
320             mExponentialBackoff.stop();
321             return;
322         }
323         Intent intent = new Intent(SatelliteService.SERVICE_INTERFACE);
324         intent.setPackage(packageName);
325 
326         mSatelliteServiceConnection = new SatelliteServiceConnection();
327         plogd("Binding to " + packageName);
328         try {
329             boolean success = mContext.bindService(
330                     intent, mSatelliteServiceConnection, Context.BIND_AUTO_CREATE);
331             if (success) {
332                 plogd("Successfully bound to the satellite service.");
333             } else {
334                 synchronized (mLock) {
335                     mIsBinding = false;
336                 }
337                 mExponentialBackoff.notifyFailed();
338                 ploge("Error binding to the satellite service. Retrying in "
339                         + mExponentialBackoff.getCurrentDelay() + " ms.");
340             }
341         } catch (Exception e) {
342             synchronized (mLock) {
343                 mIsBinding = false;
344             }
345             mExponentialBackoff.notifyFailed();
346             ploge("Exception binding to the satellite service. Retrying in "
347                     + mExponentialBackoff.getCurrentDelay() + " ms. Exception: " + e);
348         }
349     }
350 
351     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
unbindService()352     protected void unbindService() {
353         disconnectSatelliteService();
354         mContext.unbindService(mSatelliteServiceConnection);
355         mSatelliteServiceConnection = null;
356     }
357 
disconnectSatelliteService()358     private void disconnectSatelliteService() {
359         // TODO: clean up any listeners and return failed for pending callbacks
360         mSatelliteService = null;
361     }
362 
363     private class SatelliteServiceConnection implements ServiceConnection {
364         @Override
onServiceConnected(ComponentName name, IBinder service)365         public void onServiceConnected(ComponentName name, IBinder service) {
366             plogd("onServiceConnected: ComponentName=" + name);
367             synchronized (mLock) {
368                 mIsBound = true;
369                 mIsBinding = false;
370             }
371             mSatelliteService = ISatellite.Stub.asInterface(service);
372             mExponentialBackoff.stop();
373             try {
374                 mSatelliteService.setSatelliteListener(mVendorListener);
375                 mDemoSimulator.setSatelliteListener(mDemoListener);
376             } catch (RemoteException e) {
377                 // TODO: Retry setSatelliteListener
378                 plogd("setSatelliteListener: RemoteException " + e);
379             }
380             mSatelliteController.onSatelliteServiceConnected();
381         }
382 
383         @Override
onServiceDisconnected(ComponentName name)384         public void onServiceDisconnected(ComponentName name) {
385             ploge("onServiceDisconnected: Waiting for reconnect.");
386             synchronized (mLock) {
387                 mIsBinding = false;
388             }
389             // Since we are still technically bound, clear the service and wait for reconnect.
390             disconnectSatelliteService();
391         }
392 
393         @Override
onBindingDied(ComponentName name)394         public void onBindingDied(ComponentName name) {
395             ploge("onBindingDied: Unbinding and rebinding service.");
396             synchronized (mLock) {
397                 mIsBound = false;
398                 mIsBinding = false;
399             }
400             unbindService();
401             mExponentialBackoff.start();
402         }
403     }
404 
405     /**
406      * Registers for the satellite provision state changed.
407      *
408      * @param h Handler for notification message.
409      * @param what User-defined message code.
410      * @param obj User object.
411      */
registerForSatelliteProvisionStateChanged( @onNull Handler h, int what, @Nullable Object obj)412     public void registerForSatelliteProvisionStateChanged(
413             @NonNull Handler h, int what, @Nullable Object obj) {
414         mSatelliteProvisionStateChangedRegistrants.add(h, what, obj);
415     }
416 
417     /**
418      * Unregisters for the satellite provision state changed.
419      *
420      * @param h Handler to be removed from the registrant list.
421      */
unregisterForSatelliteProvisionStateChanged(@onNull Handler h)422     public void unregisterForSatelliteProvisionStateChanged(@NonNull Handler h) {
423         mSatelliteProvisionStateChangedRegistrants.remove(h);
424     }
425 
426     /**
427      * Registers for satellite position info changed from satellite modem.
428      *
429      * @param h Handler for notification message.
430      * @param what User-defined message code.
431      * @param obj User object.
432      */
registerForSatellitePositionInfoChanged( @onNull Handler h, int what, @Nullable Object obj)433     public void registerForSatellitePositionInfoChanged(
434             @NonNull Handler h, int what, @Nullable Object obj) {
435         mSatellitePositionInfoChangedRegistrants.add(h, what, obj);
436     }
437 
438     /**
439      * Unregisters for satellite position info changed from satellite modem.
440      *
441      * @param h Handler to be removed from the registrant list.
442      */
unregisterForSatellitePositionInfoChanged(@onNull Handler h)443     public void unregisterForSatellitePositionInfoChanged(@NonNull Handler h) {
444         mSatellitePositionInfoChangedRegistrants.remove(h);
445     }
446 
447     /**
448      * Registers for datagram transfer state changed.
449      *
450      * @param h Handler for notification message.
451      * @param what User-defined message code.
452      * @param obj User object.
453      */
registerForDatagramTransferStateChanged( @onNull Handler h, int what, @Nullable Object obj)454     public void registerForDatagramTransferStateChanged(
455             @NonNull Handler h, int what, @Nullable Object obj) {
456         mDatagramTransferStateChangedRegistrants.add(h, what, obj);
457     }
458 
459     /**
460      * Unregisters for datagram transfer state changed.
461      *
462      * @param h Handler to be removed from the registrant list.
463      */
unregisterForDatagramTransferStateChanged(@onNull Handler h)464     public void unregisterForDatagramTransferStateChanged(@NonNull Handler h) {
465         mDatagramTransferStateChangedRegistrants.remove(h);
466     }
467 
468     /**
469      * Registers for modem state changed from satellite modem.
470      *
471      * @param h Handler for notification message.
472      * @param what User-defined message code.
473      * @param obj User object.
474      */
registerForSatelliteModemStateChanged( @onNull Handler h, int what, @Nullable Object obj)475     public void registerForSatelliteModemStateChanged(
476             @NonNull Handler h, int what, @Nullable Object obj) {
477         mSatelliteModemStateChangedRegistrants.add(h, what, obj);
478     }
479 
480     /**
481      * Unregisters for modem state changed from satellite modem.
482      *
483      * @param h Handler to be removed from the registrant list.
484      */
unregisterForSatelliteModemStateChanged(@onNull Handler h)485     public void unregisterForSatelliteModemStateChanged(@NonNull Handler h) {
486         mSatelliteModemStateChangedRegistrants.remove(h);
487     }
488 
489     /**
490      * Registers for pending datagrams indication from satellite modem.
491      *
492      * @param h Handler for notification message.
493      * @param what User-defined message code.
494      * @param obj User object.
495      */
registerForPendingDatagrams(@onNull Handler h, int what, @Nullable Object obj)496     public void registerForPendingDatagrams(@NonNull Handler h, int what, @Nullable Object obj) {
497         mPendingDatagramsRegistrants.add(h, what, obj);
498     }
499 
500     /**
501      * Unregisters for pending datagrams indication from satellite modem.
502      *
503      * @param h Handler to be removed from the registrant list.
504      */
unregisterForPendingDatagrams(@onNull Handler h)505     public void unregisterForPendingDatagrams(@NonNull Handler h) {
506         mPendingDatagramsRegistrants.remove(h);
507     }
508 
509     /**
510      * Registers for new datagrams received from satellite modem.
511      *
512      * @param h Handler for notification message.
513      * @param what User-defined message code.
514      * @param obj User object.
515      */
registerForSatelliteDatagramsReceived( @onNull Handler h, int what, @Nullable Object obj)516     public void registerForSatelliteDatagramsReceived(
517             @NonNull Handler h, int what, @Nullable Object obj) {
518         mSatelliteDatagramsReceivedRegistrants.add(h, what, obj);
519     }
520 
521     /**
522      * Unregisters for new datagrams received from satellite modem.
523      *
524      * @param h Handler to be removed from the registrant list.
525      */
unregisterForSatelliteDatagramsReceived(@onNull Handler h)526     public void unregisterForSatelliteDatagramsReceived(@NonNull Handler h) {
527         mSatelliteDatagramsReceivedRegistrants.remove(h);
528     }
529 
530     /**
531      * Registers for non-terrestrial signal strength level changed.
532      *
533      * @param h Handler for notification message.
534      * @param what User-defined message code.
535      * @param obj User object.
536      */
registerForNtnSignalStrengthChanged( @onNull Handler h, int what, @Nullable Object obj)537     public void registerForNtnSignalStrengthChanged(
538             @NonNull Handler h, int what, @Nullable Object obj) {
539         mNtnSignalStrengthChangedRegistrants.add(h, what, obj);
540     }
541 
542     /**
543      * Unregisters for non-terrestrial signal strength level changed.
544      *
545      * @param h Handler to be removed from the registrant list.
546      */
unregisterForNtnSignalStrengthChanged(@onNull Handler h)547     public void unregisterForNtnSignalStrengthChanged(@NonNull Handler h) {
548         mNtnSignalStrengthChangedRegistrants.remove(h);
549     }
550 
551     /**
552      * Registers for satellite capabilities changed.
553      *
554      * @param h Handler for notification message.
555      * @param what User-defined message code.
556      * @param obj User object.
557      */
registerForSatelliteCapabilitiesChanged( @onNull Handler h, int what, @Nullable Object obj)558     public void registerForSatelliteCapabilitiesChanged(
559             @NonNull Handler h, int what, @Nullable Object obj) {
560         mSatelliteCapabilitiesChangedRegistrants.add(h, what, obj);
561     }
562 
563     /**
564      * Unregisters for satellite capabilities changed.
565      *
566      * @param h Handler to be removed from the registrant list.
567      */
unregisterForSatelliteCapabilitiesChanged(@onNull Handler h)568     public void unregisterForSatelliteCapabilitiesChanged(@NonNull Handler h) {
569         mSatelliteCapabilitiesChangedRegistrants.remove(h);
570     }
571 
572     /**
573      * Registers for the satellite supported state changed.
574      *
575      * @param h Handler for notification message.
576      * @param what User-defined message code.
577      * @param obj User object.
578      */
registerForSatelliteSupportedStateChanged( @onNull Handler h, int what, @Nullable Object obj)579     public void registerForSatelliteSupportedStateChanged(
580             @NonNull Handler h, int what, @Nullable Object obj) {
581         mSatelliteSupportedStateChangedRegistrants.add(h, what, obj);
582     }
583 
584     /**
585      * Unregisters for the satellite supported state changed.
586      *
587      * @param h Handler to be removed from the registrant list.
588      */
unregisterForSatelliteSupportedStateChanged(@onNull Handler h)589     public void unregisterForSatelliteSupportedStateChanged(@NonNull Handler h) {
590         mSatelliteSupportedStateChangedRegistrants.remove(h);
591     }
592 
593     /**
594      * Request to enable or disable the satellite service listening mode.
595      * Listening mode allows the satellite service to listen for incoming pages.
596      *
597      * @param enable True to enable satellite listening mode and false to disable.
598      * @param timeout How long the satellite modem should wait for the next incoming page before
599      *                disabling listening mode.
600      * @param message The Message to send to result of the operation to.
601      */
requestSatelliteListeningEnabled(boolean enable, int timeout, @Nullable Message message)602     public void requestSatelliteListeningEnabled(boolean enable, int timeout,
603             @Nullable Message message) {
604         if (mSatelliteService != null) {
605             try {
606                 mSatelliteService.requestSatelliteListeningEnabled(enable, timeout,
607                         new IIntegerConsumer.Stub() {
608                             @Override
609                             public void accept(int result) {
610                                 int error = SatelliteServiceUtils.fromSatelliteError(result);
611                                 plogd("requestSatelliteListeningEnabled: " + error);
612                                 Binder.withCleanCallingIdentity(() -> {
613                                     if (message != null) {
614                                         sendMessageWithResult(message, null, error);
615                                     }
616                                 });
617                             }
618                         });
619             } catch (RemoteException e) {
620                 ploge("requestSatelliteListeningEnabled: RemoteException " + e);
621                 if (message != null) {
622                     sendMessageWithResult(
623                             message, null, SatelliteManager.SATELLITE_RESULT_SERVICE_ERROR);
624                 }
625             }
626         } else {
627             ploge("requestSatelliteListeningEnabled: Satellite service is unavailable.");
628             if (message != null) {
629                 sendMessageWithResult(message, null,
630                         SatelliteManager.SATELLITE_RESULT_RADIO_NOT_AVAILABLE);
631             }
632         }
633     }
634 
635     /**
636      * Allow cellular modem scanning while satellite mode is on.
637      * @param enabled  {@code true} to enable cellular modem while satellite mode is on
638      * and {@code false} to disable
639      * @param message The Message to send to result of the operation to.
640      */
enableCellularModemWhileSatelliteModeIsOn(boolean enabled, @Nullable Message message)641     public void enableCellularModemWhileSatelliteModeIsOn(boolean enabled,
642             @Nullable Message message) {
643         if (mSatelliteService != null) {
644             try {
645                 IIntegerConsumer errorCallback = new IIntegerConsumer.Stub() {
646                     @Override
647                     public void accept(int result) {
648                         int error = SatelliteServiceUtils.fromSatelliteError(result);
649                         plogd("enableCellularModemWhileSatelliteModeIsOn: " + error);
650                         Binder.withCleanCallingIdentity(() -> {
651                             if (message != null) {
652                                 sendMessageWithResult(message, null, error);
653                             }
654                         });
655                     }
656                 };
657 
658                 if (mSatelliteController.isDemoModeEnabled()) {
659                     mDemoSimulator.enableCellularModemWhileSatelliteModeIsOn(
660                             enabled, errorCallback);
661                 } else {
662                     mSatelliteService.enableCellularModemWhileSatelliteModeIsOn(
663                             enabled, errorCallback);
664                 }
665             } catch (RemoteException e) {
666                 ploge("enableCellularModemWhileSatelliteModeIsOn: RemoteException " + e);
667                 if (message != null) {
668                     sendMessageWithResult(
669                             message, null, SatelliteManager.SATELLITE_RESULT_SERVICE_ERROR);
670                 }
671             }
672         } else {
673             ploge("enableCellularModemWhileSatelliteModeIsOn: Satellite service is unavailable.");
674             if (message != null) {
675                 sendMessageWithResult(message, null,
676                         SatelliteManager.SATELLITE_RESULT_RADIO_NOT_AVAILABLE);
677             }
678         }
679     }
680     /**
681      * Request to enable or disable the satellite modem and demo mode. If the satellite modem
682      * is enabled, this may also disable the cellular modem, and if the satellite modem is disabled,
683      * this may also re-enable the cellular modem.
684      *
685      * @param enableSatellite True to enable the satellite modem and false to disable.
686      * @param enableDemoMode True to enable demo mode and false to disable.
687      * @param isEmergency {@code true} to enable emergency mode, {@code false} otherwise.
688      * @param message The Message to send to result of the operation to.
689      */
requestSatelliteEnabled(boolean enableSatellite, boolean enableDemoMode, boolean isEmergency, @NonNull Message message)690     public void requestSatelliteEnabled(boolean enableSatellite, boolean enableDemoMode,
691             boolean isEmergency, @NonNull Message message) {
692         if (mSatelliteService != null) {
693             try {
694                 mSatelliteService.requestSatelliteEnabled(enableSatellite, enableDemoMode,
695                         isEmergency, new IIntegerConsumer.Stub() {
696                             @Override
697                             public void accept(int result) {
698                                 int error = SatelliteServiceUtils.fromSatelliteError(result);
699                                 plogd("setSatelliteEnabled: " + error);
700                                 Binder.withCleanCallingIdentity(() ->
701                                 sendMessageWithResult(message, null, error));
702                     }
703                 });
704             } catch (RemoteException e) {
705                 ploge("setSatelliteEnabled: RemoteException " + e);
706                 sendMessageWithResult(message, null,
707                         SatelliteManager.SATELLITE_RESULT_SERVICE_ERROR);
708             }
709         } else {
710             ploge("setSatelliteEnabled: Satellite service is unavailable.");
711             sendMessageWithResult(message, null,
712                     SatelliteManager.SATELLITE_RESULT_RADIO_NOT_AVAILABLE);
713         }
714     }
715 
716     /**
717      * Request to get whether the satellite modem is enabled.
718      *
719      * @param message The Message to send to result of the operation to.
720      */
requestIsSatelliteEnabled(@onNull Message message)721     public void requestIsSatelliteEnabled(@NonNull Message message) {
722         if (mSatelliteService != null) {
723             try {
724                 mSatelliteService.requestIsSatelliteEnabled(new IIntegerConsumer.Stub() {
725                     @Override
726                     public void accept(int result) {
727                         int error = SatelliteServiceUtils.fromSatelliteError(result);
728                         plogd("requestIsSatelliteEnabled: " + error);
729                         Binder.withCleanCallingIdentity(() ->
730                                 sendMessageWithResult(message, null, error));
731                     }
732                 }, new IBooleanConsumer.Stub() {
733                     @Override
734                     public void accept(boolean result) {
735                         // Convert for compatibility with SatelliteResponse
736                         // TODO: This should just report result instead.
737                         int[] enabled = new int[] {result ? 1 : 0};
738                         plogd("requestIsSatelliteEnabled: " + Arrays.toString(enabled));
739                         Binder.withCleanCallingIdentity(() -> sendMessageWithResult(
740                                 message, enabled, SatelliteManager.SATELLITE_RESULT_SUCCESS));
741                     }
742                 });
743             } catch (RemoteException e) {
744                 ploge("requestIsSatelliteEnabled: RemoteException " + e);
745                 sendMessageWithResult(message, null,
746                         SatelliteManager.SATELLITE_RESULT_SERVICE_ERROR);
747             }
748         } else {
749             ploge("requestIsSatelliteEnabled: Satellite service is unavailable.");
750             sendMessageWithResult(message, null,
751                     SatelliteManager.SATELLITE_RESULT_RADIO_NOT_AVAILABLE);
752         }
753     }
754 
755     /**
756      * Request to get whether the satellite service is supported on the device.
757      *
758      * @param message The Message to send to result of the operation to.
759      */
requestIsSatelliteSupported(@onNull Message message)760     public void requestIsSatelliteSupported(@NonNull Message message) {
761         if (mSatelliteService != null) {
762             try {
763                 mSatelliteService.requestIsSatelliteSupported(new IIntegerConsumer.Stub() {
764                     @Override
765                     public void accept(int result) {
766                         int error = SatelliteServiceUtils.fromSatelliteError(result);
767                         plogd("requestIsSatelliteSupported: " + error);
768                         Binder.withCleanCallingIdentity(() ->
769                                 sendMessageWithResult(message, null, error));
770                     }
771                 }, new IBooleanConsumer.Stub() {
772                     @Override
773                     public void accept(boolean result) {
774                         plogd("requestIsSatelliteSupported: " + result);
775                         Binder.withCleanCallingIdentity(() -> sendMessageWithResult(
776                                 message, result, SatelliteManager.SATELLITE_RESULT_SUCCESS));
777                     }
778                 });
779             } catch (RemoteException e) {
780                 ploge("requestIsSatelliteSupported: RemoteException " + e);
781                 sendMessageWithResult(message, null,
782                         SatelliteManager.SATELLITE_RESULT_SERVICE_ERROR);
783             }
784         } else {
785             ploge("requestIsSatelliteSupported: Satellite service is unavailable.");
786             sendMessageWithResult(
787                     message, null, SatelliteManager.SATELLITE_RESULT_RADIO_NOT_AVAILABLE);
788         }
789     }
790 
791     /**
792      * Request to get the SatelliteCapabilities of the satellite service.
793      *
794      * @param message The Message to send to result of the operation to.
795      */
requestSatelliteCapabilities(@onNull Message message)796     public void requestSatelliteCapabilities(@NonNull Message message) {
797         if (mSatelliteService != null) {
798             try {
799                 mSatelliteService.requestSatelliteCapabilities(new IIntegerConsumer.Stub() {
800                     @Override
801                     public void accept(int result) {
802                         int error = SatelliteServiceUtils.fromSatelliteError(result);
803                         plogd("requestSatelliteCapabilities: " + error);
804                         Binder.withCleanCallingIdentity(() ->
805                                 sendMessageWithResult(message, null, error));
806                     }
807                 }, new ISatelliteCapabilitiesConsumer.Stub() {
808                     @Override
809                     public void accept(android.telephony.satellite.stub.SatelliteCapabilities
810                             result) {
811                         SatelliteCapabilities capabilities =
812                                 SatelliteServiceUtils.fromSatelliteCapabilities(result);
813                         plogd("requestSatelliteCapabilities: " + capabilities);
814                         Binder.withCleanCallingIdentity(() -> sendMessageWithResult(
815                                 message, capabilities, SatelliteManager.SATELLITE_RESULT_SUCCESS));
816                     }
817                 });
818             } catch (RemoteException e) {
819                 ploge("requestSatelliteCapabilities: RemoteException " + e);
820                 sendMessageWithResult(message, null,
821                         SatelliteManager.SATELLITE_RESULT_SERVICE_ERROR);
822             }
823         } else {
824             ploge("requestSatelliteCapabilities: Satellite service is unavailable.");
825             sendMessageWithResult(message, null,
826                     SatelliteManager.SATELLITE_RESULT_RADIO_NOT_AVAILABLE);
827         }
828     }
829 
830     /**
831      * User started pointing to the satellite.
832      * The satellite service should report the satellite pointing info via
833      * ISatelliteListener#onSatellitePositionChanged as the user device/satellite moves.
834      *
835      * @param message The Message to send to result of the operation to.
836      */
startSendingSatellitePointingInfo(@onNull Message message)837     public void startSendingSatellitePointingInfo(@NonNull Message message) {
838         if (mSatelliteService != null) {
839             try {
840                 mSatelliteService.startSendingSatellitePointingInfo(new IIntegerConsumer.Stub() {
841                     @Override
842                     public void accept(int result) {
843                         int error = SatelliteServiceUtils.fromSatelliteError(result);
844                         plogd("startSendingSatellitePointingInfo: " + error);
845                         Binder.withCleanCallingIdentity(() ->
846                                 sendMessageWithResult(message, null, error));
847                     }
848                 });
849             } catch (RemoteException e) {
850                 ploge("startSendingSatellitePointingInfo: RemoteException " + e);
851                 sendMessageWithResult(message, null,
852                         SatelliteManager.SATELLITE_RESULT_SERVICE_ERROR);
853             }
854         } else {
855             ploge("startSendingSatellitePointingInfo: Satellite service is unavailable.");
856             sendMessageWithResult(message, null,
857                     SatelliteManager.SATELLITE_RESULT_RADIO_NOT_AVAILABLE);
858         }
859     }
860 
861     /**
862      * User stopped pointing to the satellite.
863      * The satellite service should stop reporting satellite pointing info to the framework.
864      *
865      * @param message The Message to send to result of the operation to.
866      */
stopSendingSatellitePointingInfo(@onNull Message message)867     public void stopSendingSatellitePointingInfo(@NonNull Message message) {
868         if (mSatelliteService != null) {
869             try {
870                 mSatelliteService.stopSendingSatellitePointingInfo(new IIntegerConsumer.Stub() {
871                     @Override
872                     public void accept(int result) {
873                         int error = SatelliteServiceUtils.fromSatelliteError(result);
874                         plogd("stopSendingSatellitePointingInfo: " + error);
875                         Binder.withCleanCallingIdentity(() ->
876                                 sendMessageWithResult(message, null, error));
877                     }
878                 });
879             } catch (RemoteException e) {
880                 ploge("stopSendingSatellitePointingInfo: RemoteException " + e);
881                 sendMessageWithResult(message, null,
882                         SatelliteManager.SATELLITE_RESULT_SERVICE_ERROR);
883             }
884         } else {
885             ploge("stopSendingSatellitePointingInfo: Satellite service is unavailable.");
886             sendMessageWithResult(message, null,
887                     SatelliteManager.SATELLITE_RESULT_RADIO_NOT_AVAILABLE);
888         }
889     }
890 
891     /**
892      * Provision the device with a satellite provider.
893      * This is needed if the provider allows dynamic registration.
894      * Once provisioned, ISatelliteListener#onSatelliteProvisionStateChanged should report true.
895      *
896      * @param token The token to be used as a unique identifier for provisioning with satellite
897      *              gateway.
898      * @param provisionData Data from the provisioning app that can be used by provisioning server
899      * @param message The Message to send to result of the operation to.
900      */
provisionSatelliteService(@onNull String token, @NonNull byte[] provisionData, @NonNull Message message)901     public void provisionSatelliteService(@NonNull String token, @NonNull byte[] provisionData,
902             @NonNull Message message) {
903         if (mSatelliteService != null) {
904             try {
905                 mSatelliteService.provisionSatelliteService(token, provisionData,
906                         new IIntegerConsumer.Stub() {
907                             @Override
908                             public void accept(int result) {
909                                 int error = SatelliteServiceUtils.fromSatelliteError(result);
910                                 plogd("provisionSatelliteService: " + error);
911                                 Binder.withCleanCallingIdentity(() ->
912                                         sendMessageWithResult(message, null, error));
913                             }
914                         });
915             } catch (RemoteException e) {
916                 ploge("provisionSatelliteService: RemoteException " + e);
917                 sendMessageWithResult(message, null,
918                         SatelliteManager.SATELLITE_RESULT_SERVICE_ERROR);
919             }
920         } else {
921             ploge("provisionSatelliteService: Satellite service is unavailable.");
922             sendMessageWithResult(message, null,
923                     SatelliteManager.SATELLITE_RESULT_RADIO_NOT_AVAILABLE);
924         }
925     }
926 
927     /**
928      * Deprovision the device with the satellite provider.
929      * This is needed if the provider allows dynamic registration.
930      * Once deprovisioned, ISatelliteListener#onSatelliteProvisionStateChanged should report false.
931      *
932      * @param token The token of the device/subscription to be deprovisioned.
933      * @param message The Message to send to result of the operation to.
934      */
deprovisionSatelliteService(@onNull String token, @NonNull Message message)935     public void deprovisionSatelliteService(@NonNull String token, @NonNull Message message) {
936         if (mSatelliteService != null) {
937             try {
938                 mSatelliteService.deprovisionSatelliteService(token, new IIntegerConsumer.Stub() {
939                     @Override
940                     public void accept(int result) {
941                         int error = SatelliteServiceUtils.fromSatelliteError(result);
942                         plogd("deprovisionSatelliteService: " + error);
943                         Binder.withCleanCallingIdentity(() ->
944                                 sendMessageWithResult(message, null, error));
945                     }
946                 });
947             } catch (RemoteException e) {
948                 ploge("deprovisionSatelliteService: RemoteException " + e);
949                 sendMessageWithResult(message, null,
950                         SatelliteManager.SATELLITE_RESULT_SERVICE_ERROR);
951             }
952         } else {
953             ploge("deprovisionSatelliteService: Satellite service is unavailable.");
954             sendMessageWithResult(message, null,
955                     SatelliteManager.SATELLITE_RESULT_RADIO_NOT_AVAILABLE);
956         }
957     }
958 
959     /**
960      * Request to get whether this device is provisioned with a satellite provider.
961      *
962      * @param message The Message to send to result of the operation to.
963      */
requestIsSatelliteProvisioned(@onNull Message message)964     public void requestIsSatelliteProvisioned(@NonNull Message message) {
965         if (mSatelliteService != null) {
966             try {
967                 mSatelliteService.requestIsSatelliteProvisioned(new IIntegerConsumer.Stub() {
968                     @Override
969                     public void accept(int result) {
970                         int error = SatelliteServiceUtils.fromSatelliteError(result);
971                         plogd("requestIsSatelliteProvisioned: " + error);
972                         Binder.withCleanCallingIdentity(() ->
973                                 sendMessageWithResult(message, null, error));
974                     }
975                 }, new IBooleanConsumer.Stub() {
976                     @Override
977                     public void accept(boolean result) {
978                         // Convert for compatibility with SatelliteResponse
979                         // TODO: This should just report result instead.
980                         int[] provisioned = new int[] {result ? 1 : 0};
981                         plogd("requestIsSatelliteProvisioned: " + Arrays.toString(provisioned));
982                         Binder.withCleanCallingIdentity(() -> sendMessageWithResult(
983                                 message, provisioned, SatelliteManager.SATELLITE_RESULT_SUCCESS));
984                     }
985                 });
986             } catch (RemoteException e) {
987                 ploge("requestIsSatelliteProvisioned: RemoteException " + e);
988                 sendMessageWithResult(message, null,
989                         SatelliteManager.SATELLITE_RESULT_SERVICE_ERROR);
990             }
991         } else {
992             ploge("requestIsSatelliteProvisioned: Satellite service is unavailable.");
993             sendMessageWithResult(message, null,
994                     SatelliteManager.SATELLITE_RESULT_RADIO_NOT_AVAILABLE);
995         }
996     }
997 
998     /**
999      * Poll the pending datagrams to be received over satellite.
1000      * The satellite service should check if there are any pending datagrams to be received over
1001      * satellite and report them via ISatelliteListener#onSatelliteDatagramsReceived.
1002      *
1003      * @param message The Message to send to result of the operation to.
1004      */
pollPendingSatelliteDatagrams(@onNull Message message)1005     public void pollPendingSatelliteDatagrams(@NonNull Message message) {
1006         if (mSatelliteService != null) {
1007             try {
1008                 mSatelliteService.pollPendingSatelliteDatagrams(new IIntegerConsumer.Stub() {
1009                     @Override
1010                     public void accept(int result) {
1011                         int error = SatelliteServiceUtils.fromSatelliteError(result);
1012                         plogd("pollPendingDatagrams: " + error);
1013                         Binder.withCleanCallingIdentity(() ->
1014                                 sendMessageWithResult(message, null, error));
1015                     }
1016                 });
1017             } catch (RemoteException e) {
1018                 ploge("pollPendingDatagrams: RemoteException " + e);
1019                 sendMessageWithResult(message, null,
1020                         SatelliteManager.SATELLITE_RESULT_SERVICE_ERROR);
1021             }
1022         } else {
1023             ploge("pollPendingDatagrams: Satellite service is unavailable.");
1024             sendMessageWithResult(message, null,
1025                     SatelliteManager.SATELLITE_RESULT_RADIO_NOT_AVAILABLE);
1026         }
1027     }
1028 
1029     /**
1030      * Send datagram over satellite.
1031      *
1032      * @param datagram Datagram to send in byte format.
1033      * @param isEmergency Whether this is an emergency datagram.
1034      * @param needFullScreenPointingUI this is used to indicate pointingUI app to open in
1035      *                                 full screen mode.
1036      * @param message The Message to send to result of the operation to.
1037      */
sendSatelliteDatagram(@onNull SatelliteDatagram datagram, boolean isEmergency, boolean needFullScreenPointingUI, @NonNull Message message)1038     public void sendSatelliteDatagram(@NonNull SatelliteDatagram datagram, boolean isEmergency,
1039             boolean needFullScreenPointingUI, @NonNull Message message) {
1040         if (mSatelliteService != null) {
1041             try {
1042                 mSatelliteService.sendSatelliteDatagram(
1043                         SatelliteServiceUtils.toSatelliteDatagram(datagram), isEmergency,
1044                         new IIntegerConsumer.Stub() {
1045                             @Override
1046                             public void accept(int result) {
1047                                 int error = SatelliteServiceUtils.fromSatelliteError(result);
1048                                 plogd("sendDatagram: " + error);
1049                                 Binder.withCleanCallingIdentity(() ->
1050                                         sendMessageWithResult(message, null, error));
1051                             }
1052                         });
1053             } catch (RemoteException e) {
1054                 ploge("sendDatagram: RemoteException " + e);
1055                 sendMessageWithResult(message, null,
1056                         SatelliteManager.SATELLITE_RESULT_SERVICE_ERROR);
1057             }
1058         } else {
1059             ploge("sendDatagram: Satellite service is unavailable.");
1060             sendMessageWithResult(message, null,
1061                     SatelliteManager.SATELLITE_RESULT_RADIO_NOT_AVAILABLE);
1062         }
1063     }
1064 
1065     /**
1066      * Request the current satellite modem state.
1067      * The satellite service should report the current satellite modem state via
1068      * ISatelliteListener#onSatelliteModemStateChanged.
1069      *
1070      * @param message The Message to send to result of the operation to.
1071      */
requestSatelliteModemState(@onNull Message message)1072     public void requestSatelliteModemState(@NonNull Message message) {
1073         if (mSatelliteService != null) {
1074             try {
1075                 mSatelliteService.requestSatelliteModemState(new IIntegerConsumer.Stub() {
1076                     @Override
1077                     public void accept(int result) {
1078                         int error = SatelliteServiceUtils.fromSatelliteError(result);
1079                         plogd("requestSatelliteModemState: " + error);
1080                         Binder.withCleanCallingIdentity(() ->
1081                                 sendMessageWithResult(message, null, error));
1082                     }
1083                 }, new IIntegerConsumer.Stub() {
1084                     @Override
1085                     public void accept(int result) {
1086                         // Convert SatelliteModemState from service to frameworks definition.
1087                         int modemState = SatelliteServiceUtils.fromSatelliteModemState(result);
1088                         plogd("requestSatelliteModemState: " + modemState);
1089                         Binder.withCleanCallingIdentity(() -> sendMessageWithResult(
1090                                 message, modemState, SatelliteManager.SATELLITE_RESULT_SUCCESS));
1091                     }
1092                 });
1093             } catch (RemoteException e) {
1094                 ploge("requestSatelliteModemState: RemoteException " + e);
1095                 sendMessageWithResult(message, null,
1096                         SatelliteManager.SATELLITE_RESULT_SERVICE_ERROR);
1097             }
1098         } else {
1099             ploge("requestSatelliteModemState: Satellite service is unavailable.");
1100             sendMessageWithResult(message, null,
1101                     SatelliteManager.SATELLITE_RESULT_RADIO_NOT_AVAILABLE);
1102         }
1103     }
1104 
1105     /**
1106      * Request to get the time after which the satellite will be visible. This is an int
1107      * representing the duration in seconds after which the satellite will be visible.
1108      * This will return 0 if the satellite is currently visible.
1109      *
1110      * @param message The Message to send to result of the operation to.
1111      */
requestTimeForNextSatelliteVisibility(@onNull Message message)1112     public void requestTimeForNextSatelliteVisibility(@NonNull Message message) {
1113         if (mSatelliteService != null) {
1114             try {
1115                 mSatelliteService.requestTimeForNextSatelliteVisibility(
1116                         new IIntegerConsumer.Stub() {
1117                             @Override
1118                             public void accept(int result) {
1119                                 int error = SatelliteServiceUtils.fromSatelliteError(result);
1120                                 plogd("requestTimeForNextSatelliteVisibility: " + error);
1121                                 Binder.withCleanCallingIdentity(() ->
1122                                         sendMessageWithResult(message, null, error));
1123                             }
1124                         }, new IIntegerConsumer.Stub() {
1125                             @Override
1126                             public void accept(int result) {
1127                                 // Convert for compatibility with SatelliteResponse
1128                                 // TODO: This should just report result instead.
1129                                 int[] time = new int[] {result};
1130                                 plogd("requestTimeForNextSatelliteVisibility: "
1131                                         + Arrays.toString(time));
1132                                 Binder.withCleanCallingIdentity(() -> sendMessageWithResult(
1133                                         message, time, SatelliteManager.SATELLITE_RESULT_SUCCESS));
1134                             }
1135                         });
1136             } catch (RemoteException e) {
1137                 ploge("requestTimeForNextSatelliteVisibility: RemoteException " + e);
1138                 sendMessageWithResult(message, null,
1139                         SatelliteManager.SATELLITE_RESULT_SERVICE_ERROR);
1140             }
1141         } else {
1142             ploge("requestTimeForNextSatelliteVisibility: Satellite service is unavailable.");
1143             sendMessageWithResult(message, null,
1144                     SatelliteManager.SATELLITE_RESULT_RADIO_NOT_AVAILABLE);
1145         }
1146     }
1147 
1148     /**
1149      * Set the non-terrestrial PLMN with lower priority than terrestrial networks.
1150      * MCC/MNC broadcast by the non-terrestrial networks will not be included in OPLMNwACT file
1151      * on SIM profile.
1152      * Acquisition of satellite based system is deemed lower priority to terrestrial networks.
1153      * Even so, UE shall make all attempts to acquire terrestrial service prior to camping on
1154      * satellite LTE service.
1155      *
1156      * @param simSlot Indicates the SIM slot to which this API will be applied. The modem will use
1157      *                this information to determine the relevant carrier.
1158      * @param carrierPlmnList The list of roaming PLMN used for connecting to satellite networks
1159      *                        supported by user subscription.
1160      * @param allSatellitePlmnList Modem should use the allSatellitePlmnList to identify satellite
1161      *                             PLMNs that are not supported by the carrier and make sure not to
1162      *                             attach to them.
1163      * @param message The result receiver that returns whether the modem has
1164      *                successfully set the satellite PLMN
1165      */
setSatellitePlmn(@onNull int simSlot, @NonNull List<String> carrierPlmnList, @NonNull List<String> allSatellitePlmnList, @NonNull Message message)1166     public void setSatellitePlmn(@NonNull int simSlot, @NonNull List<String> carrierPlmnList,
1167             @NonNull List<String> allSatellitePlmnList, @NonNull Message message) {
1168         if (mSatelliteService != null) {
1169             try {
1170                 mSatelliteService.setSatellitePlmn(simSlot, carrierPlmnList, allSatellitePlmnList,
1171                         new IIntegerConsumer.Stub() {
1172                             @Override
1173                             public void accept(int result) {
1174                                 int error = SatelliteServiceUtils.fromSatelliteError(result);
1175                                 plogd("setSatellitePlmn: " + error);
1176                                 Binder.withCleanCallingIdentity(() ->
1177                                         sendMessageWithResult(message, null, error));
1178                             }
1179                         });
1180             } catch (RemoteException e) {
1181                 ploge("setSatellitePlmn: RemoteException " + e);
1182                 sendMessageWithResult(message, null,
1183                         SatelliteManager.SATELLITE_RESULT_SERVICE_ERROR);
1184             }
1185         } else {
1186             ploge("setSatellitePlmn: Satellite service is unavailable.");
1187             sendMessageWithResult(message, null,
1188                     SatelliteManager.SATELLITE_RESULT_RADIO_NOT_AVAILABLE);
1189         }
1190     }
1191 
1192     /**
1193      * Enable or disable satellite in the cellular modem associated with a carrier.
1194      * Refer setSatellitePlmn for the details of satellite PLMN scanning process.
1195      *
1196      * @param simSlot Indicates the SIM slot to which this API will be applied. The modem will use
1197      *                this information to determine the relevant carrier.
1198      * @param enableSatellite True to enable the satellite modem and false to disable.
1199      * @param message The Message to send to result of the operation to.
1200      */
requestSetSatelliteEnabledForCarrier(@onNull int simSlot, @NonNull boolean enableSatellite, @NonNull Message message)1201     public void requestSetSatelliteEnabledForCarrier(@NonNull int simSlot,
1202             @NonNull boolean enableSatellite, @NonNull Message message) {
1203         if (mSatelliteService != null) {
1204             try {
1205                 mSatelliteService.setSatelliteEnabledForCarrier(simSlot, enableSatellite,
1206                         new IIntegerConsumer.Stub() {
1207                             @Override
1208                             public void accept(int result) {
1209                                 int error = SatelliteServiceUtils.fromSatelliteError(result);
1210                                 plogd("requestSetSatelliteEnabledForCarrier: " + error);
1211                                 Binder.withCleanCallingIdentity(() ->
1212                                         sendMessageWithResult(message, null, error));
1213                             }
1214                         });
1215             } catch (RemoteException e) {
1216                 ploge("requestSetSatelliteEnabledForCarrier: RemoteException " + e);
1217                 sendMessageWithResult(message, null,
1218                         SatelliteManager.SATELLITE_RESULT_SERVICE_ERROR);
1219             }
1220         } else {
1221             ploge("requestSetSatelliteEnabledForCarrier: Satellite service is unavailable.");
1222             sendMessageWithResult(message, null,
1223                     SatelliteManager.SATELLITE_RESULT_REQUEST_NOT_SUPPORTED);
1224         }
1225     }
1226 
1227     /**
1228      * Check whether satellite is enabled in the cellular modem associated with a carrier.
1229      *
1230      * @param simSlot Indicates the SIM slot to which this API will be applied. The modem will use
1231      *                this information to determine the relevant carrier.
1232      * @param message The Message to send to result of the operation to.
1233      */
requestIsSatelliteEnabledForCarrier(@onNull int simSlot, @NonNull Message message)1234     public void requestIsSatelliteEnabledForCarrier(@NonNull int simSlot,
1235             @NonNull Message message) {
1236         if (mSatelliteService != null) {
1237             try {
1238                 mSatelliteService.requestIsSatelliteEnabledForCarrier(simSlot,
1239                         new IIntegerConsumer.Stub() {
1240                             @Override
1241                             public void accept(int result) {
1242                                 int error = SatelliteServiceUtils.fromSatelliteError(result);
1243                                 plogd("requestIsSatelliteEnabledForCarrier: " + error);
1244                                 Binder.withCleanCallingIdentity(() ->
1245                                         sendMessageWithResult(message, null, error));
1246                             }
1247                         }, new IBooleanConsumer.Stub() {
1248                             @Override
1249                             public void accept(boolean result) {
1250                                 // Convert for compatibility with SatelliteResponse
1251                                 // TODO: This should just report result instead.
1252                                 int[] enabled = new int[] {result ? 1 : 0};
1253                                 plogd("requestIsSatelliteEnabledForCarrier: "
1254                                         + Arrays.toString(enabled));
1255                                 Binder.withCleanCallingIdentity(() -> sendMessageWithResult(
1256                                         message, enabled,
1257                                         SatelliteManager.SATELLITE_RESULT_SUCCESS));
1258                             }
1259                         });
1260             } catch (RemoteException e) {
1261                 ploge("requestIsSatelliteEnabledForCarrier: RemoteException " + e);
1262                 sendMessageWithResult(message, null,
1263                         SatelliteManager.SATELLITE_RESULT_SERVICE_ERROR);
1264             }
1265         } else {
1266             ploge("requestIsSatelliteEnabledForCarrier: Satellite service is unavailable.");
1267             sendMessageWithResult(message, null,
1268                     SatelliteManager.SATELLITE_RESULT_RADIO_NOT_AVAILABLE);
1269         }
1270     }
1271 
1272     /**
1273      * Request to get the signal strength of the satellite connection.
1274      *
1275      * @param message The Message to send to result of the operation to.
1276      */
requestNtnSignalStrength(@onNull Message message)1277     public void requestNtnSignalStrength(@NonNull Message message) {
1278         if (mSatelliteService != null) {
1279             try {
1280                 mSatelliteService.requestSignalStrength(
1281                         new IIntegerConsumer.Stub() {
1282                             @Override
1283                             public void accept(int result) {
1284                                 int error = SatelliteServiceUtils.fromSatelliteError(result);
1285                                 plogd("requestNtnSignalStrength: " + error);
1286                                 Binder.withCleanCallingIdentity(() ->
1287                                         sendMessageWithResult(message, null, error));
1288                             }
1289                         }, new INtnSignalStrengthConsumer.Stub() {
1290                             @Override
1291                             public void accept(
1292                                     android.telephony.satellite.stub.NtnSignalStrength result) {
1293                                 NtnSignalStrength ntnSignalStrength =
1294                                         SatelliteServiceUtils.fromNtnSignalStrength(result);
1295                                 plogd("requestNtnSignalStrength: " + ntnSignalStrength);
1296                                 Binder.withCleanCallingIdentity(() -> sendMessageWithResult(
1297                                         message, ntnSignalStrength,
1298                                         SatelliteManager.SATELLITE_RESULT_SUCCESS));
1299                             }
1300                         });
1301             } catch (RemoteException e) {
1302                 ploge("requestNtnSignalStrength: RemoteException " + e);
1303                 sendMessageWithResult(message, null,
1304                         SatelliteManager.SATELLITE_RESULT_SERVICE_ERROR);
1305             }
1306         } else {
1307             ploge("requestNtnSignalStrength: Satellite service is unavailable.");
1308             sendMessageWithResult(message, null,
1309                     SatelliteManager.SATELLITE_RESULT_RADIO_NOT_AVAILABLE);
1310         }
1311     }
1312 
1313     /**
1314      * The satellite service should report the NTN signal strength via
1315      * ISatelliteListener#onNtnSignalStrengthChanged when the NTN signal strength changes.
1316      *
1317      * @param message The Message to send to result of the operation to.
1318      */
startSendingNtnSignalStrength(@onNull Message message)1319     public void startSendingNtnSignalStrength(@NonNull Message message) {
1320         if (mSatelliteService != null) {
1321             try {
1322                 mSatelliteService.startSendingNtnSignalStrength(new IIntegerConsumer.Stub() {
1323                     @Override
1324                     public void accept(int result) {
1325                         int error = SatelliteServiceUtils.fromSatelliteError(result);
1326                         plogd("startSendingNtnSignalStrength: " + error);
1327                         Binder.withCleanCallingIdentity(() ->
1328                                 sendMessageWithResult(message, null, error));
1329                     }
1330                 });
1331             } catch (RemoteException e) {
1332                 ploge("startSendingNtnSignalStrength: RemoteException " + e);
1333                 sendMessageWithResult(message, null,
1334                         SatelliteManager.SATELLITE_RESULT_SERVICE_ERROR);
1335             }
1336         } else {
1337             ploge("startSendingNtnSignalStrength: Satellite service is unavailable.");
1338             sendMessageWithResult(message, null,
1339                     SatelliteManager.SATELLITE_RESULT_RADIO_NOT_AVAILABLE);
1340         }
1341     }
1342 
1343     /**
1344      * The satellite service should stop reporting NTN signal strength to the framework.
1345      *
1346      * @param message The Message to send to result of the operation to.
1347      */
stopSendingNtnSignalStrength(@onNull Message message)1348     public void stopSendingNtnSignalStrength(@NonNull Message message) {
1349         if (mSatelliteService != null) {
1350             try {
1351                 mSatelliteService.stopSendingNtnSignalStrength(new IIntegerConsumer.Stub() {
1352                     @Override
1353                     public void accept(int result) {
1354                         int error = SatelliteServiceUtils.fromSatelliteError(result);
1355                         plogd("stopSendingNtnSignalStrength: " + error);
1356                         Binder.withCleanCallingIdentity(() ->
1357                                 sendMessageWithResult(message, null, error));
1358                     }
1359                 });
1360             } catch (RemoteException e) {
1361                 ploge("stopSendingNtnSignalStrength: RemoteException " + e);
1362                 sendMessageWithResult(message, null,
1363                         SatelliteManager.SATELLITE_RESULT_SERVICE_ERROR);
1364             }
1365         } else {
1366             ploge("stopSendingNtnSignalStrength: Satellite service is unavailable.");
1367             sendMessageWithResult(message, null,
1368                     SatelliteManager.SATELLITE_RESULT_RADIO_NOT_AVAILABLE);
1369         }
1370     }
1371 
1372     /**
1373      * The satellite service should abort all datagram-sending requests.
1374      *
1375      * @param message The Message to send to result of the operation to.
1376      */
abortSendingSatelliteDatagrams(@onNull Message message)1377     public void abortSendingSatelliteDatagrams(@NonNull Message message) {
1378         if (mSatelliteService != null) {
1379             try {
1380                 mSatelliteService.abortSendingSatelliteDatagrams(new IIntegerConsumer.Stub() {
1381                     @Override
1382                     public void accept(int result) {
1383                         int error = SatelliteServiceUtils.fromSatelliteError(result);
1384                         plogd("abortSendingSatelliteDatagrams: " + error);
1385                         Binder.withCleanCallingIdentity(() ->
1386                                 sendMessageWithResult(message, null, error));
1387                     }
1388                 });
1389             } catch (RemoteException e) {
1390                 ploge("abortSendingSatelliteDatagrams: RemoteException " + e);
1391                 sendMessageWithResult(message, null,
1392                         SatelliteManager.SATELLITE_RESULT_SERVICE_ERROR);
1393             }
1394         } else {
1395             ploge("abortSendingSatelliteDatagrams: Satellite service is unavailable.");
1396             sendMessageWithResult(message, null,
1397                     SatelliteManager.SATELLITE_RESULT_RADIO_NOT_AVAILABLE);
1398         }
1399     }
1400 
isSatelliteServiceSupported()1401     public boolean isSatelliteServiceSupported() {
1402         return mIsSatelliteServiceSupported;
1403     }
1404 
1405     /** Check if vendor satellite service is connected */
isSatelliteServiceConnected()1406     public boolean isSatelliteServiceConnected() {
1407         synchronized (mLock) {
1408             return (mSatelliteService != null);
1409         }
1410     }
1411 
1412     /**
1413      * This API can be used by only CTS to update satellite vendor service package name.
1414      *
1415      * @param servicePackageName The package name of the satellite vendor service.
1416      * @return {@code true} if the satellite vendor service is set successfully,
1417      * {@code false} otherwise.
1418      */
1419     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
setSatelliteServicePackageName(@ullable String servicePackageName)1420     public void setSatelliteServicePackageName(@Nullable String servicePackageName) {
1421         plogd("setSatelliteServicePackageName: config_satellite_service_package is "
1422                 + "updated, new packageName=" + servicePackageName);
1423         mExponentialBackoff.stop();
1424         if (mSatelliteServiceConnection != null) {
1425             synchronized (mLock) {
1426                 mIsBound = false;
1427                 mIsBinding = false;
1428             }
1429             unbindService();
1430         }
1431 
1432         if (servicePackageName == null || servicePackageName.equals("null")) {
1433             mVendorSatellitePackageName = "";
1434         } else {
1435             mVendorSatellitePackageName = servicePackageName;
1436         }
1437         mIsSatelliteServiceSupported = getSatelliteServiceSupport();
1438         bindService();
1439         mExponentialBackoff.start();
1440     }
1441 
1442     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
sendMessageWithResult(@onNull Message message, @Nullable Object result, @SatelliteManager.SatelliteResult int error)1443     protected static void sendMessageWithResult(@NonNull Message message, @Nullable Object result,
1444             @SatelliteManager.SatelliteResult int error) {
1445         SatelliteException exception = error == SatelliteManager.SATELLITE_RESULT_SUCCESS
1446                 ? null : new SatelliteException(error);
1447         AsyncResult.forMessage(message, result, exception);
1448         message.sendToTarget();
1449     }
1450 
logd(@onNull String log)1451     private static void logd(@NonNull String log) {
1452         Rlog.d(TAG, log);
1453     }
1454 
loge(@onNull String log)1455     private static void loge(@NonNull String log) {
1456         Rlog.e(TAG, log);
1457     }
1458 
isSatellitePersistentLoggingEnabled( @onNull Context context, @NonNull FeatureFlags featureFlags)1459     private boolean isSatellitePersistentLoggingEnabled(
1460             @NonNull Context context, @NonNull FeatureFlags featureFlags) {
1461         if (featureFlags.satellitePersistentLogging()) {
1462             return true;
1463         }
1464         try {
1465             return context.getResources().getBoolean(
1466                     R.bool.config_dropboxmanager_persistent_logging_enabled);
1467         } catch (RuntimeException e) {
1468             return false;
1469         }
1470     }
1471 
plogd(@onNull String log)1472     private void plogd(@NonNull String log) {
1473         Rlog.d(TAG, log);
1474         if (mPersistentLogger != null) {
1475             mPersistentLogger.debug(TAG, log);
1476         }
1477     }
1478 
ploge(@onNull String log)1479     private void ploge(@NonNull String log) {
1480         Rlog.e(TAG, log);
1481         if (mPersistentLogger != null) {
1482             mPersistentLogger.error(TAG, log);
1483         }
1484     }
1485 }
1486