• 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 android.telephony.satellite;
18 
19 import android.Manifest;
20 import android.annotation.CallbackExecutor;
21 import android.annotation.FlaggedApi;
22 import android.annotation.Hide;
23 import android.annotation.IntDef;
24 import android.annotation.NonNull;
25 import android.annotation.Nullable;
26 import android.annotation.RequiresFeature;
27 import android.annotation.RequiresPermission;
28 import android.annotation.SystemApi;
29 import android.annotation.SystemService;
30 import android.content.Context;
31 import android.content.pm.PackageManager;
32 import android.os.Binder;
33 import android.os.Bundle;
34 import android.os.CancellationSignal;
35 import android.os.ICancellationSignal;
36 import android.os.OutcomeReceiver;
37 import android.os.RemoteException;
38 import android.os.ResultReceiver;
39 import android.telephony.CarrierConfigManager;
40 import android.telephony.SubscriptionManager;
41 import android.telephony.TelephonyCallback;
42 import android.telephony.TelephonyFrameworkInitializer;
43 import android.telephony.TelephonyManager;
44 import android.telephony.TelephonyRegistryManager;
45 
46 import com.android.internal.telephony.IBooleanConsumer;
47 import com.android.internal.telephony.IIntegerConsumer;
48 import com.android.internal.telephony.ITelephony;
49 import com.android.internal.telephony.IVoidConsumer;
50 import com.android.internal.telephony.flags.Flags;
51 import com.android.telephony.Rlog;
52 
53 import java.lang.annotation.Retention;
54 import java.lang.annotation.RetentionPolicy;
55 import java.time.Duration;
56 import java.util.ArrayList;
57 import java.util.Arrays;
58 import java.util.HashSet;
59 import java.util.List;
60 import java.util.Objects;
61 import java.util.Set;
62 import java.util.concurrent.ConcurrentHashMap;
63 import java.util.concurrent.Executor;
64 import java.util.function.Consumer;
65 import java.util.stream.Collectors;
66 
67 /**
68  * Manages satellite states such as monitoring enabled state and operations such as provisioning,
69  * pointing, messaging, location sharing, etc.
70  *
71  * <p>To get the object, call {@link Context#getSystemService(String)} with
72  * {@link Context#SATELLITE_SERVICE}.
73  *
74  * <p>SatelliteManager is intended for use on devices with feature
75  * {@link PackageManager#FEATURE_TELEPHONY_SATELLITE}. On devices without the feature, the behavior
76  * is not reliable.
77  */
78 @SystemService(Context.SATELLITE_SERVICE)
79 @FlaggedApi(Flags.FLAG_SATELLITE_STATE_CHANGE_LISTENER)
80 @RequiresFeature(PackageManager.FEATURE_TELEPHONY_SATELLITE)
81 public final class SatelliteManager {
82     private static final String TAG = "SatelliteManager";
83 
84     private static final ConcurrentHashMap<SatelliteDatagramCallback, ISatelliteDatagramCallback>
85             sSatelliteDatagramCallbackMap = new ConcurrentHashMap<>();
86     private static final ConcurrentHashMap<SatelliteProvisionStateCallback,
87             ISatelliteProvisionStateCallback> sSatelliteProvisionStateCallbackMap =
88             new ConcurrentHashMap<>();
89     private static final ConcurrentHashMap<SatelliteModemStateCallback,
90             ISatelliteModemStateCallback>
91             sSatelliteModemStateCallbackMap = new ConcurrentHashMap<>();
92     private static final ConcurrentHashMap<SatelliteTransmissionUpdateCallback,
93             ISatelliteTransmissionUpdateCallback> sSatelliteTransmissionUpdateCallbackMap =
94             new ConcurrentHashMap<>();
95     private static final ConcurrentHashMap<NtnSignalStrengthCallback, INtnSignalStrengthCallback>
96             sNtnSignalStrengthCallbackMap = new ConcurrentHashMap<>();
97     private static final ConcurrentHashMap<SatelliteCapabilitiesCallback,
98             ISatelliteCapabilitiesCallback>
99             sSatelliteCapabilitiesCallbackMap = new ConcurrentHashMap<>();
100     private static final ConcurrentHashMap<Consumer<Boolean>,
101             IBooleanConsumer> sSatelliteSupportedStateCallbackMap =
102             new ConcurrentHashMap<>();
103     private static final ConcurrentHashMap<SatelliteCommunicationAccessStateCallback,
104             ISatelliteCommunicationAccessStateCallback>
105             sSatelliteCommunicationAccessStateCallbackMap =
106             new ConcurrentHashMap<>();
107     private static final ConcurrentHashMap<SatelliteDisallowedReasonsCallback,
108             ISatelliteDisallowedReasonsCallback>
109             sSatelliteDisallowedReasonsCallbackMap =
110             new ConcurrentHashMap<>();
111     private static final ConcurrentHashMap<SelectedNbIotSatelliteSubscriptionCallback,
112             ISelectedNbIotSatelliteSubscriptionCallback>
113             sSelectedNbIotSatelliteSubscriptionCallbackMap =
114             new ConcurrentHashMap<>();
115 
116     private final int mSubId;
117 
118     /**
119      * Context this SatelliteManager is for.
120      */
121     @Nullable private final Context mContext;
122 
123     private TelephonyRegistryManager mTelephonyRegistryMgr;
124 
125     /**
126      * Create an instance of the SatelliteManager.
127      *
128      * @param context The context the SatelliteManager belongs to.
129      * @hide
130      */
SatelliteManager(@ullable Context context)131     public SatelliteManager(@Nullable Context context) {
132         this(context, SubscriptionManager.DEFAULT_SUBSCRIPTION_ID);
133     }
134 
135     /**
136      * Create an instance of the SatelliteManager associated with a particular subscription.
137      *
138      * @param context The context the SatelliteManager belongs to.
139      * @param subId The subscription ID associated with the SatelliteManager.
140      */
SatelliteManager(@ullable Context context, int subId)141     private SatelliteManager(@Nullable Context context, int subId) {
142         mContext = context;
143         mSubId = subId;
144     }
145 
146     /**
147      * Exception from the satellite service containing the {@link SatelliteResult} error code.
148      * @hide
149      */
150     @SystemApi
151     public static class SatelliteException extends Exception {
152         @SatelliteResult private final int mErrorCode;
153 
154         /**
155          * Create a SatelliteException with a given error code.
156          *
157          * @param errorCode The {@link SatelliteResult}.
158          */
SatelliteException(@atelliteResult int errorCode)159         public SatelliteException(@SatelliteResult int errorCode) {
160             mErrorCode = errorCode;
161         }
162 
163         /**
164          * Get the error code returned from the satellite service.
165          *
166          * @return The {@link SatelliteResult}.
167          */
getErrorCode()168         @SatelliteResult public int getErrorCode() {
169             return mErrorCode;
170         }
171     }
172 
173     /**
174      * Bundle key to get the response from
175      * {@link #requestIsEnabled(Executor, OutcomeReceiver)}.
176      * @hide
177      */
178 
179     public static final String KEY_SATELLITE_ENABLED = "satellite_enabled";
180 
181     /**
182      * Bundle key to get the response from
183      * {@link #requestIsDemoModeEnabled(Executor, OutcomeReceiver)}.
184      * @hide
185      */
186 
187     public static final String KEY_DEMO_MODE_ENABLED = "demo_mode_enabled";
188 
189     /**
190      * Bundle key to get the response from
191      * {@link #requestIsEmergencyModeEnabled(Executor, OutcomeReceiver)}.
192      * @hide
193      */
194     public static final String KEY_EMERGENCY_MODE_ENABLED = "emergency_mode_enabled";
195 
196     /**
197      * Bundle key to get the response from
198      * {@link #requestIsSupported(Executor, OutcomeReceiver)}.
199      * @hide
200      */
201 
202     public static final String KEY_SATELLITE_SUPPORTED = "satellite_supported";
203 
204     /**
205      * Bundle key to get the response from
206      * {@link #requestCapabilities(Executor, OutcomeReceiver)}.
207      * @hide
208      */
209 
210     public static final String KEY_SATELLITE_CAPABILITIES = "satellite_capabilities";
211 
212     /**
213      * Bundle key to get the response from
214      * {@link #requestSessionStats(Executor, OutcomeReceiver)}.
215      * @hide
216      */
217 
218     public static final String KEY_SESSION_STATS = "session_stats";
219 
220     /**
221      * Bundle key to get the response from
222      * {@link #requestSessionStats(Executor, OutcomeReceiver)}.
223      * @hide
224      */
225 
226     public static final String KEY_SESSION_STATS_V2 = "session_stats_v2";
227 
228     /**
229      * Bundle key to get the response from
230      * {@link #requestIsProvisioned(Executor, OutcomeReceiver)}.
231      * @hide
232      */
233 
234     public static final String KEY_SATELLITE_PROVISIONED = "satellite_provisioned";
235 
236     /**
237      * Bundle key to get the response from
238      * {@link #requestIsCommunicationAllowedForCurrentLocation(Executor, OutcomeReceiver)}.
239      * @hide
240      */
241 
242     public static final String KEY_SATELLITE_COMMUNICATION_ALLOWED =
243             "satellite_communication_allowed";
244 
245     /**
246      * Bundle key to get the response from
247      * {@link #requestTimeForNextSatelliteVisibility(Executor, OutcomeReceiver)}.
248      * @hide
249      */
250 
251     public static final String KEY_SATELLITE_NEXT_VISIBILITY = "satellite_next_visibility";
252 
253     /**
254      * Bundle key to get the response from
255      * {@link #requestNtnSignalStrength(Executor, OutcomeReceiver)}.
256      * @hide
257      */
258 
259     public static final String KEY_NTN_SIGNAL_STRENGTH = "ntn_signal_strength";
260 
261     /**
262      * Bundle key to get the response from
263      * {@link #requestSatelliteSubscriberProvisionStatus(Executor, OutcomeReceiver)}.
264      * @hide
265      */
266     public static final String KEY_REQUEST_PROVISION_SUBSCRIBER_ID_TOKEN =
267             "request_provision_subscriber_id";
268 
269     /**
270      * Bundle key to get the response from
271      * {@link #provisionSatellite(List, Executor, OutcomeReceiver)}.
272      * @hide
273      */
274     public static final String KEY_PROVISION_SATELLITE_TOKENS = "provision_satellite";
275 
276     /**
277      * Bundle key to get the response from
278      * {@link #deprovisionSatellite(List, Executor, OutcomeReceiver)}.
279      * @hide
280      */
281     public static final String KEY_DEPROVISION_SATELLITE_TOKENS = "deprovision_satellite";
282 
283     /**
284      * Bundle key to get the response from
285      * {@link #requestSatelliteAccessConfigurationForCurrentLocation(Executor, OutcomeReceiver)}.
286      * @hide
287      */
288     public static final String KEY_SATELLITE_ACCESS_CONFIGURATION =
289             "satellite_access_configuration";
290 
291     /**
292      * Bundle key to get the response from
293      * {@link #requestSatelliteDisplayName(Executor, OutcomeReceiver)}.
294      * @hide
295      */
296     public static final String KEY_SATELLITE_DISPLAY_NAME = "satellite_display_name";
297 
298     /**
299      * Bundle key to get the response from
300      * {@link #requestSelectedNbIotSatelliteSubscriptionId(Executor, OutcomeReceiver)}.
301      * @hide
302      */
303     public static final String KEY_SELECTED_NB_IOT_SATELLITE_SUBSCRIPTION_ID =
304             "selected_nb_iot_satellite_subscription_id";
305 
306     /**
307      * The request was successfully processed.
308      * @hide
309      */
310     @SystemApi
311     public static final int SATELLITE_RESULT_SUCCESS = 0;
312 
313     /**
314      * A generic error which should be used only when other specific errors cannot be used.
315      * @hide
316      */
317     @SystemApi
318     public static final int SATELLITE_RESULT_ERROR = 1;
319 
320     /**
321      * Error received from the satellite server.
322      * @hide
323      */
324     @SystemApi
325     public static final int SATELLITE_RESULT_SERVER_ERROR = 2;
326 
327     /**
328      * Error received from the vendor service. This generic error code should be used
329      * only when the error cannot be mapped to other specific service error codes.
330      * @hide
331      */
332     @SystemApi
333     public static final int SATELLITE_RESULT_SERVICE_ERROR = 3;
334 
335     /**
336      * Error received from satellite modem. This generic error code should be used only when
337      * the error cannot be mapped to other specific modem error codes.
338      * @hide
339      */
340     @SystemApi
341     public static final int SATELLITE_RESULT_MODEM_ERROR = 4;
342 
343     /**
344      * Error received from the satellite network. This generic error code should be used only when
345      * the error cannot be mapped to other specific network error codes.
346      * @hide
347      */
348     @SystemApi
349     public static final int SATELLITE_RESULT_NETWORK_ERROR = 5;
350 
351     /**
352      * Telephony is not in a valid state to receive requests from clients.
353      * @hide
354      */
355     @SystemApi
356     public static final int SATELLITE_RESULT_INVALID_TELEPHONY_STATE = 6;
357 
358     /**
359      * Satellite modem is not in a valid state to receive requests from clients.
360      * @hide
361      */
362     @SystemApi
363     public static final int SATELLITE_RESULT_INVALID_MODEM_STATE = 7;
364 
365     /**
366      * Either vendor service, or modem, or Telephony framework has received a request with
367      * invalid arguments from its clients.
368      * @hide
369      */
370     @SystemApi
371     public static final int SATELLITE_RESULT_INVALID_ARGUMENTS = 8;
372 
373     /**
374      * Telephony framework failed to send a request or receive a response from the vendor service
375      * or satellite modem due to internal error.
376      * @hide
377      */
378     @SystemApi
379     public static final int SATELLITE_RESULT_REQUEST_FAILED = 9;
380 
381     /**
382      * Radio did not start or is resetting.
383      * @hide
384      */
385     @SystemApi
386     public static final int SATELLITE_RESULT_RADIO_NOT_AVAILABLE = 10;
387 
388     /**
389      * The request is not supported by either the satellite modem or the network.
390      * @hide
391      */
392     @SystemApi
393     public static final int SATELLITE_RESULT_REQUEST_NOT_SUPPORTED = 11;
394 
395     /**
396      * Satellite modem or network has no resources available to handle requests from clients.
397      * @hide
398      */
399     @SystemApi
400     public static final int SATELLITE_RESULT_NO_RESOURCES = 12;
401 
402     /**
403      * Satellite service is not provisioned yet.
404      * @hide
405      */
406     @SystemApi
407     public static final int SATELLITE_RESULT_SERVICE_NOT_PROVISIONED = 13;
408 
409     /**
410      * Satellite service provision is already in progress.
411      * @hide
412      */
413     @SystemApi
414     public static final int SATELLITE_RESULT_SERVICE_PROVISION_IN_PROGRESS = 14;
415 
416     /**
417      * The ongoing request was aborted by either the satellite modem or the network.
418      * This error is also returned when framework decides to abort current send request as one
419      * of the previous send request failed.
420      * @hide
421      */
422     @SystemApi
423     public static final int SATELLITE_RESULT_REQUEST_ABORTED = 15;
424 
425     /**
426      * The device/subscriber is barred from accessing the satellite service.
427      * @hide
428      */
429     @SystemApi
430     public static final int SATELLITE_RESULT_ACCESS_BARRED = 16;
431 
432     /**
433      * Satellite modem timeout to receive ACK or response from the satellite network after
434      * sending a request to the network.
435      * @hide
436      */
437     @SystemApi
438     public static final int SATELLITE_RESULT_NETWORK_TIMEOUT = 17;
439 
440     /**
441      * Satellite network is not reachable from the modem.
442      * @hide
443      */
444     @SystemApi
445     public static final int SATELLITE_RESULT_NOT_REACHABLE = 18;
446 
447     /**
448      * The device/subscriber is not authorized to register with the satellite service provider.
449      * @hide
450      */
451     @SystemApi
452     public static final int SATELLITE_RESULT_NOT_AUTHORIZED = 19;
453 
454     /**
455      * The device does not support satellite.
456      * @hide
457      */
458     @SystemApi
459     public static final int SATELLITE_RESULT_NOT_SUPPORTED = 20;
460 
461     /**
462      * The current request is already in-progress.
463      * @hide
464      */
465     @SystemApi
466     public static final int SATELLITE_RESULT_REQUEST_IN_PROGRESS = 21;
467 
468     /**
469      * Satellite modem is currently busy due to which current request cannot be processed.
470      * @hide
471      */
472     @SystemApi
473     public static final int SATELLITE_RESULT_MODEM_BUSY = 22;
474 
475     /**
476      * Telephony process is not currently available or satellite is not supported.
477      * @hide
478      */
479     @SystemApi
480     public static final int SATELLITE_RESULT_ILLEGAL_STATE = 23;
481 
482     /**
483      * Telephony framework timeout to receive ACK or response from the satellite modem after
484      * sending a request to the modem.
485      * @hide
486      */
487     @SystemApi
488     public static final int SATELLITE_RESULT_MODEM_TIMEOUT = 24;
489 
490     /**
491      * Telephony framework needs to access the current location of the device to perform the
492      * request. However, location in the settings is disabled by users.
493      * @hide
494      */
495     @SystemApi
496     @FlaggedApi(Flags.FLAG_SATELLITE_SYSTEM_APIS)
497     public static final int SATELLITE_RESULT_LOCATION_DISABLED = 25;
498 
499     /**
500      * Telephony framework needs to access the current location of the device to perform the
501      * request. However, Telephony fails to fetch the current location from location service.
502      * @hide
503      */
504     @SystemApi
505     @FlaggedApi(Flags.FLAG_SATELLITE_SYSTEM_APIS)
506     public static final int SATELLITE_RESULT_LOCATION_NOT_AVAILABLE = 26;
507 
508     /**
509      * Emergency call is in progress.
510      * @hide
511      */
512     @SystemApi
513     @FlaggedApi(Flags.FLAG_SATELLITE_SYSTEM_APIS)
514     public static final int SATELLITE_RESULT_EMERGENCY_CALL_IN_PROGRESS = 27;
515 
516     /**
517      * Disabling satellite is in progress.
518      * @hide
519      */
520     @SystemApi
521     @FlaggedApi(Flags.FLAG_SATELLITE_SYSTEM_APIS)
522     public static final int SATELLITE_RESULT_DISABLE_IN_PROGRESS = 28;
523 
524     /**
525      * Enabling satellite is in progress.
526      * @hide
527      */
528     @SystemApi
529     @FlaggedApi(Flags.FLAG_SATELLITE_SYSTEM_APIS)
530     public static final int SATELLITE_RESULT_ENABLE_IN_PROGRESS = 29;
531 
532     /**
533      * There is no valid satellite subscription selected.
534      * @hide
535      */
536     @SystemApi
537     @FlaggedApi(Flags.FLAG_SATELLITE_SYSTEM_APIS)
538     public static final int SATELLITE_RESULT_NO_VALID_SATELLITE_SUBSCRIPTION = 30;
539 
540     /** @hide */
541     @IntDef(prefix = {"SATELLITE_RESULT_"}, value = {
542             SATELLITE_RESULT_SUCCESS,
543             SATELLITE_RESULT_ERROR,
544             SATELLITE_RESULT_SERVER_ERROR,
545             SATELLITE_RESULT_SERVICE_ERROR,
546             SATELLITE_RESULT_MODEM_ERROR,
547             SATELLITE_RESULT_NETWORK_ERROR,
548             SATELLITE_RESULT_INVALID_TELEPHONY_STATE,
549             SATELLITE_RESULT_INVALID_MODEM_STATE,
550             SATELLITE_RESULT_INVALID_ARGUMENTS,
551             SATELLITE_RESULT_REQUEST_FAILED,
552             SATELLITE_RESULT_RADIO_NOT_AVAILABLE,
553             SATELLITE_RESULT_REQUEST_NOT_SUPPORTED,
554             SATELLITE_RESULT_NO_RESOURCES,
555             SATELLITE_RESULT_SERVICE_NOT_PROVISIONED,
556             SATELLITE_RESULT_SERVICE_PROVISION_IN_PROGRESS,
557             SATELLITE_RESULT_REQUEST_ABORTED,
558             SATELLITE_RESULT_ACCESS_BARRED,
559             SATELLITE_RESULT_NETWORK_TIMEOUT,
560             SATELLITE_RESULT_NOT_REACHABLE,
561             SATELLITE_RESULT_NOT_AUTHORIZED,
562             SATELLITE_RESULT_NOT_SUPPORTED,
563             SATELLITE_RESULT_REQUEST_IN_PROGRESS,
564             SATELLITE_RESULT_MODEM_BUSY,
565             SATELLITE_RESULT_ILLEGAL_STATE,
566             SATELLITE_RESULT_MODEM_TIMEOUT,
567             SATELLITE_RESULT_LOCATION_DISABLED,
568             SATELLITE_RESULT_LOCATION_NOT_AVAILABLE,
569             SATELLITE_RESULT_EMERGENCY_CALL_IN_PROGRESS,
570             SATELLITE_RESULT_DISABLE_IN_PROGRESS,
571             SATELLITE_RESULT_ENABLE_IN_PROGRESS,
572             SATELLITE_RESULT_NO_VALID_SATELLITE_SUBSCRIPTION
573     })
574     @Retention(RetentionPolicy.SOURCE)
575     public @interface SatelliteResult {}
576 
577     /**
578      * Unknown Non-Terrestrial radio technology. This generic radio technology should be used
579      * only when the radio technology cannot be mapped to other specific radio technologies.
580      * @hide
581      */
582     @SystemApi
583     public static final int NT_RADIO_TECHNOLOGY_UNKNOWN = 0;
584 
585     /**
586      * 3GPP NB-IoT (Narrowband Internet of Things) over Non-Terrestrial-Networks technology.
587      * @hide
588      */
589     @SystemApi
590     public static final int NT_RADIO_TECHNOLOGY_NB_IOT_NTN = 1;
591 
592     /**
593      * 3GPP 5G NR over Non-Terrestrial-Networks technology.
594      * @hide
595      */
596     @SystemApi
597     public static final int NT_RADIO_TECHNOLOGY_NR_NTN = 2;
598 
599     /**
600      * 3GPP eMTC (enhanced Machine-Type Communication) over Non-Terrestrial-Networks technology.
601      * @hide
602      */
603     @SystemApi
604     public static final int NT_RADIO_TECHNOLOGY_EMTC_NTN = 3;
605 
606     /**
607      * Proprietary technology.
608      * @hide
609      */
610     @SystemApi
611     public static final int NT_RADIO_TECHNOLOGY_PROPRIETARY = 4;
612 
613     /** @hide */
614     @IntDef(prefix = "NT_RADIO_TECHNOLOGY_", value = {
615             NT_RADIO_TECHNOLOGY_UNKNOWN,
616             NT_RADIO_TECHNOLOGY_NB_IOT_NTN,
617             NT_RADIO_TECHNOLOGY_NR_NTN,
618             NT_RADIO_TECHNOLOGY_EMTC_NTN,
619             NT_RADIO_TECHNOLOGY_PROPRIETARY
620     })
621     @Retention(RetentionPolicy.SOURCE)
622     public @interface NTRadioTechnology {}
623 
624     /**
625      * Suggested device hold position is unknown.
626      * @hide
627      */
628     @SystemApi
629     public static final int DEVICE_HOLD_POSITION_UNKNOWN = 0;
630 
631     /**
632      * User is suggested to hold the device in portrait mode.
633      * @hide
634      */
635     @SystemApi
636     public static final int DEVICE_HOLD_POSITION_PORTRAIT = 1;
637 
638     /**
639      * User is suggested to hold the device in landscape mode with left hand.
640      * @hide
641      */
642     @SystemApi
643     public static final int DEVICE_HOLD_POSITION_LANDSCAPE_LEFT = 2;
644 
645     /**
646      * User is suggested to hold the device in landscape mode with right hand.
647      * @hide
648      */
649     @SystemApi
650     public static final int DEVICE_HOLD_POSITION_LANDSCAPE_RIGHT = 3;
651 
652     /** @hide */
653     @IntDef(prefix = {"DEVICE_HOLD_POSITION_"}, value = {
654             DEVICE_HOLD_POSITION_UNKNOWN,
655             DEVICE_HOLD_POSITION_PORTRAIT,
656             DEVICE_HOLD_POSITION_LANDSCAPE_LEFT,
657             DEVICE_HOLD_POSITION_LANDSCAPE_RIGHT
658        })
659     @Retention(RetentionPolicy.SOURCE)
660     public @interface DeviceHoldPosition {}
661 
662     /**
663      *  Display mode is unknown.
664      * @hide
665      */
666     @SystemApi
667     public static final int DISPLAY_MODE_UNKNOWN = 0;
668 
669     /**
670      * Display mode of the device used for satellite communication for non-foldable phones.
671      * @hide
672      */
673     @SystemApi
674     public static final int DISPLAY_MODE_FIXED = 1;
675 
676     /**
677      * Display mode of the device used for satellite communication for foldabale phones when the
678      * device is opened.
679      * @hide
680      */
681     @SystemApi
682     public static final int DISPLAY_MODE_OPENED = 2;
683 
684     /**
685      * Display mode of the device used for satellite communication for foldabable phones when the
686      * device is closed.
687      * @hide
688      */
689     @SystemApi
690     public static final int DISPLAY_MODE_CLOSED = 3;
691 
692     /** @hide */
693     @IntDef(prefix = {"ANTENNA_POSITION_"}, value = {
694             DISPLAY_MODE_UNKNOWN,
695             DISPLAY_MODE_FIXED,
696             DISPLAY_MODE_OPENED,
697             DISPLAY_MODE_CLOSED
698     })
699     @Retention(RetentionPolicy.SOURCE)
700     public @interface DisplayMode {}
701 
702     /**
703      * Unknown or unsupported value for data mode on satellite.
704      * @hide
705      */
706     @SystemApi
707     @FlaggedApi(Flags.FLAG_SATELLITE_25Q4_APIS)
708     public static final int SATELLITE_DATA_SUPPORT_UNKNOWN = -1;
709 
710     /**
711      * Support only restricted data usecases like carrier messaging using RCS.
712      * @hide
713      */
714     @SystemApi
715     @FlaggedApi(Flags.FLAG_SATELLITE_25Q4_APIS)
716     public static final int SATELLITE_DATA_SUPPORT_RESTRICTED = 0;
717 
718     /**
719      * Support constrained internet which would enable internet only for applications that are
720      * modified.
721      *
722      * <p>
723      * To get internet access, applications need to be modified to use the satellite data
724      * optimized network. This can be done by setting the {@link #PROPERTY_SATELLITE_DATA_OPTIMIZED}
725      * property to {@code true} in the manifest.
726      * </p>
727      *
728      * @hide
729      */
730     @SystemApi
731     @FlaggedApi(Flags.FLAG_SATELLITE_25Q4_APIS)
732     public static final int SATELLITE_DATA_SUPPORT_CONSTRAINED = 1;
733 
734     /**
735      * Support default internet on satellite without any restrictions on any apps.
736      * @hide
737      */
738     @SystemApi
739     @FlaggedApi(Flags.FLAG_SATELLITE_25Q4_APIS)
740     public static final int SATELLITE_DATA_SUPPORT_UNCONSTRAINED = 2;
741 
742     /** @hide */
743     @IntDef(prefix = {"SATELLITE_DATA_SUPPORT_"}, value = {
744         SATELLITE_DATA_SUPPORT_UNKNOWN,
745         SATELLITE_DATA_SUPPORT_RESTRICTED,
746         SATELLITE_DATA_SUPPORT_CONSTRAINED,
747         SATELLITE_DATA_SUPPORT_UNCONSTRAINED,
748     })
749     @Retention(RetentionPolicy.SOURCE)
750     public @interface SatelliteDataSupportMode {}
751 
752     /**
753      * The emergency call is handed over to oem-enabled satellite SOS messaging. SOS messages are
754      * sent to SOS providers, which will then forward the messages to emergency providers.
755      * @hide
756      */
757     @SystemApi
758     public static final int EMERGENCY_CALL_TO_SATELLITE_HANDOVER_TYPE_SOS = 1;
759 
760     /**
761      * The emergency call is handed over to carrier-enabled satellite T911 messaging. T911 messages
762      * are sent directly to local emergency providers.
763      * @hide
764      */
765     @SystemApi
766     public static final int EMERGENCY_CALL_TO_SATELLITE_HANDOVER_TYPE_T911 = 2;
767 
768     /**
769      * This intent will be broadcasted if there are any change to list of subscriber information.
770      * This intent will be sent only to the app with component defined in
771      * config_satellite_carrier_roaming_esos_provisioned_class and package defined in
772      * config_satellite_gateway_service_package
773      * @hide
774      */
775     @SystemApi
776     @FlaggedApi(Flags.FLAG_SATELLITE_SYSTEM_APIS)
777     public static final String ACTION_SATELLITE_SUBSCRIBER_ID_LIST_CHANGED =
778             "android.telephony.satellite.action.SATELLITE_SUBSCRIBER_ID_LIST_CHANGED";
779 
780 
781     /**
782      * This intent will be broadcasted to start a non-emergency session.
783      * This intent will be sent only to the app with component defined in
784      * config_satellite_carrier_roaming_non_emergency_session_class and package defined in
785      * config_satellite_gateway_service_package
786      * @hide
787      */
788     @SystemApi
789     @FlaggedApi(Flags.FLAG_SATELLITE_SYSTEM_APIS)
790     public static final String ACTION_SATELLITE_START_NON_EMERGENCY_SESSION =
791             "android.telephony.satellite.action.SATELLITE_START_NON_EMERGENCY_SESSION";
792 
793     /**
794      * Application level {@link android.content.pm.PackageManager.Property} tag that represents
795      * whether the application supports P2P SMS over carrier roaming satellite which needs manual
796      * trigger to connect to satellite. The messaging applications that supports P2P SMS over
797      * carrier roaming satellite should set value of this property to {@code true}.
798      *
799      * <p><b>Syntax:</b>
800      * <pre>
801      * &lt;application&gt;
802      *   &lt;property
803      *     android:name="android.telephony.satellite.PROPERTY_SATELLITE_MANUAL_CONNECT_P2P_SUPPORT"
804      *     android:value="true"/&gt;
805      * &lt;/application&gt;
806      * </pre>
807      * @hide
808      */
809     @SystemApi
810     @FlaggedApi(Flags.FLAG_SATELLITE_SYSTEM_APIS)
811     public static final String PROPERTY_SATELLITE_MANUAL_CONNECT_P2P_SUPPORT =
812             "android.telephony.satellite.PROPERTY_SATELLITE_MANUAL_CONNECT_P2P_SUPPORT";
813 
814     /**
815      * Meta-data represents whether the application supports P2P SMS over carrier roaming satellite
816      * which needs manual trigger to connect to satellite. The messaging applications that supports
817      * P2P SMS over carrier roaming satellites should add the following in their AndroidManifest.
818      * {@code
819      * <application
820      *   <meta-data
821      *     android:name="android.telephony.METADATA_SATELLITE_MANUAL_CONNECT_P2P_SUPPORT"
822      *     android:value="true"/>
823      * </application>
824      * }
825      * @hide
826      */
827     public static final String METADATA_SATELLITE_MANUAL_CONNECT_P2P_SUPPORT =
828             "android.telephony.METADATA_SATELLITE_MANUAL_CONNECT_P2P_SUPPORT";
829 
830     /**
831      * A boolean value indicating whether application is optimized to utilize low bandwidth
832      * satellite data.
833      * The applications that are optimized for low bandwidth satellite data should set this
834      * property to {@code true} in the manifest to indicate to platform about the same.
835      * {@code
836      * <application>
837      *   <meta-data
838      *     android:name="android.telephony.PROPERTY_SATELLITE_DATA_OPTIMIZED"
839      *     android:value="true"/>
840      * </application>
841      * }
842      * <p>
843      * When {@code true}, satellite data optimized network is available for applications.
844      */
845     @FlaggedApi(Flags.FLAG_SATELLITE_25Q4_APIS)
846     public static final String PROPERTY_SATELLITE_DATA_OPTIMIZED =
847             "android.telephony.PROPERTY_SATELLITE_DATA_OPTIMIZED";
848 
849     /**
850      * Registers a {@link SatelliteStateChangeListener} to receive callbacks when the satellite
851      * state may have changed.
852      *
853      * <p>The callback method is immediately triggered with latest state on invoking this method if
854      * the state change has been notified before.
855      *
856      * @param executor The {@link Executor} where the {@code listener} will be invoked
857      * @param listener The listener to monitor the satellite state change
858      *
859      * @see SatelliteStateChangeListener
860      * @see TelephonyManager#hasCarrierPrivileges()
861      */
862     @FlaggedApi(Flags.FLAG_SATELLITE_STATE_CHANGE_LISTENER)
863     @RequiresPermission(anyOf = {android.Manifest.permission.READ_BASIC_PHONE_STATE,
864             android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE,
865             android.Manifest.permission.READ_PHONE_STATE,
866             "carrier privileges"})
registerStateChangeListener(@onNull @allbackExecutor Executor executor, @NonNull SatelliteStateChangeListener listener)867     public void registerStateChangeListener(@NonNull @CallbackExecutor Executor executor,
868             @NonNull SatelliteStateChangeListener listener) {
869         if (mContext == null) {
870             throw new IllegalStateException("Telephony service is null");
871         }
872 
873         mTelephonyRegistryMgr = mContext.getSystemService(TelephonyRegistryManager.class);
874         if (mTelephonyRegistryMgr == null) {
875             throw new IllegalStateException("Telephony registry service is null");
876         }
877         mTelephonyRegistryMgr.addSatelliteStateChangeListener(executor, listener);
878     }
879 
880     /**
881      * Unregisters the {@link SatelliteStateChangeListener} previously registered with
882      * {@link #registerStateChangeListener(Executor, SatelliteStateChangeListener)}.
883      *
884      * <p>It will be a no-op if the {@code listener} is not currently registered.
885      *
886      * @param listener The listener to unregister
887      *
888      * @see SatelliteStateChangeListener
889      * @see TelephonyManager#hasCarrierPrivileges()
890      */
891     @FlaggedApi(Flags.FLAG_SATELLITE_STATE_CHANGE_LISTENER)
892     @RequiresPermission(anyOf = {android.Manifest.permission.READ_BASIC_PHONE_STATE,
893             android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE,
894             android.Manifest.permission.READ_PHONE_STATE,
895             "carrier privileges"})
unregisterStateChangeListener(@onNull SatelliteStateChangeListener listener)896     public void unregisterStateChangeListener(@NonNull SatelliteStateChangeListener listener) {
897         if (mContext == null) {
898             throw new IllegalStateException("Telephony service is null");
899         }
900 
901         mTelephonyRegistryMgr = mContext.getSystemService(TelephonyRegistryManager.class);
902         if (mTelephonyRegistryMgr == null) {
903             throw new IllegalStateException("Telephony registry service is null");
904         }
905         mTelephonyRegistryMgr.removeSatelliteStateChangeListener(listener);
906     }
907 
908     /**
909      * Request to enable or disable the satellite modem and demo mode.
910      * If satellite modem and cellular modem cannot work concurrently,
911      * then this will disable the cellular modem if satellite modem is enabled,
912      * and will re-enable the cellular modem if satellite modem is disabled.
913      *
914      * Demo mode is created to simulate the experience of sending and receiving messages over
915      * satellite. If user enters demo mode, a request should be sent to framework to enable
916      * satellite with enableDemoMode set to {code true}. Once satellite is enabled and device is
917      * aligned with the satellite, user can send a message and also receive a reply in demo mode.
918      * If enableSatellite is {@code false}, enableDemoMode has no impact on the behavior.
919      *
920      * @param attributes The attributes of the enable request.
921      * @param executor The executor on which the error code listener will be called.
922      * @param resultListener Listener for the {@link SatelliteResult} result of the operation.
923      *
924      * @throws SecurityException if the caller doesn't have required permission.
925      *
926      * @hide
927      */
928     @SystemApi
929     @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
requestEnabled(@onNull EnableRequestAttributes attributes, @NonNull @CallbackExecutor Executor executor, @SatelliteResult @NonNull Consumer<Integer> resultListener)930     public void requestEnabled(@NonNull EnableRequestAttributes attributes,
931             @NonNull @CallbackExecutor Executor executor,
932             @SatelliteResult @NonNull Consumer<Integer> resultListener) {
933         Objects.requireNonNull(attributes);
934         Objects.requireNonNull(executor);
935         Objects.requireNonNull(resultListener);
936 
937         try {
938             ITelephony telephony = getITelephony();
939             if (telephony != null) {
940                 IIntegerConsumer errorCallback = new IIntegerConsumer.Stub() {
941                     @Override
942                     public void accept(int result) {
943                         executor.execute(() -> Binder.withCleanCallingIdentity(
944                                 () -> resultListener.accept(result)));
945                     }
946                 };
947                 telephony.requestSatelliteEnabled(attributes.isEnabled(),
948                         attributes.isDemoMode(), attributes.isEmergencyMode(), errorCallback);
949             } else {
950                 Rlog.e(TAG, "requestEnabled() invalid telephony");
951                 executor.execute(() -> Binder.withCleanCallingIdentity(
952                         () -> resultListener.accept(SATELLITE_RESULT_ILLEGAL_STATE)));
953             }
954         } catch (RemoteException ex) {
955             Rlog.e(TAG, "requestEnabled() exception: ", ex);
956             executor.execute(() -> Binder.withCleanCallingIdentity(
957                     () -> resultListener.accept(SATELLITE_RESULT_ILLEGAL_STATE)));
958         }
959     }
960 
961     /**
962      * Request to get whether the satellite modem is enabled.
963      *
964      * @param executor The executor on which the callback will be called.
965      * @param callback The callback object to which the result will be delivered.
966      *                 If the request is successful, {@link OutcomeReceiver#onResult(Object)}
967      *                 will return a {@code boolean} with value {@code true} if the satellite modem
968      *                 is enabled and {@code false} otherwise.
969      *                 If the request is not successful, {@link OutcomeReceiver#onError(Throwable)}
970      *                 will return a {@link SatelliteException} with the {@link SatelliteResult}.
971      *
972      * @throws SecurityException if the caller doesn't have required permission.
973      *
974      * @hide
975      */
976     @SystemApi
977     @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
requestIsEnabled(@onNull @allbackExecutor Executor executor, @NonNull OutcomeReceiver<Boolean, SatelliteException> callback)978     public void requestIsEnabled(@NonNull @CallbackExecutor Executor executor,
979             @NonNull OutcomeReceiver<Boolean, SatelliteException> callback) {
980         Objects.requireNonNull(executor);
981         Objects.requireNonNull(callback);
982 
983         try {
984             ITelephony telephony = getITelephony();
985             if (telephony != null) {
986                 ResultReceiver receiver = new ResultReceiver(null) {
987                     @Override
988                     protected void onReceiveResult(int resultCode, Bundle resultData) {
989                         if (resultCode == SATELLITE_RESULT_SUCCESS) {
990                             if (resultData.containsKey(KEY_SATELLITE_ENABLED)) {
991                                 boolean isSatelliteEnabled =
992                                         resultData.getBoolean(KEY_SATELLITE_ENABLED);
993                                 executor.execute(() -> Binder.withCleanCallingIdentity(() ->
994                                         callback.onResult(isSatelliteEnabled)));
995                             } else {
996                                 loge("KEY_SATELLITE_ENABLED does not exist.");
997                                 executor.execute(() -> Binder.withCleanCallingIdentity(() ->
998                                         callback.onError(new SatelliteException(
999                                                 SATELLITE_RESULT_REQUEST_FAILED))));
1000                             }
1001                         } else {
1002                             executor.execute(() -> Binder.withCleanCallingIdentity(() ->
1003                                     callback.onError(new SatelliteException(resultCode))));
1004                         }
1005                     }
1006                 };
1007                 telephony.requestIsSatelliteEnabled(receiver);
1008             } else {
1009                 loge("requestIsEnabled() invalid telephony");
1010                 executor.execute(() -> Binder.withCleanCallingIdentity(() -> callback.onError(
1011                         new SatelliteException(SATELLITE_RESULT_ILLEGAL_STATE))));
1012             }
1013         } catch (RemoteException ex) {
1014             loge("requestIsEnabled() RemoteException: " + ex);
1015             executor.execute(() -> Binder.withCleanCallingIdentity(() -> callback.onError(
1016                     new SatelliteException(SATELLITE_RESULT_ILLEGAL_STATE))));
1017         }
1018     }
1019 
1020     /**
1021      * Request to get whether the satellite service demo mode is enabled.
1022      *
1023      * @param executor The executor on which the callback will be called.
1024      * @param callback The callback object to which the result will be delivered.
1025      *                 If the request is successful, {@link OutcomeReceiver#onResult(Object)}
1026      *                 will return a {@code boolean} with value {@code true} if demo mode is enabled
1027      *                 and {@code false} otherwise.
1028      *                 If the request is not successful, {@link OutcomeReceiver#onError(Throwable)}
1029      *                 will return a {@link SatelliteException} with the {@link SatelliteResult}.
1030      *
1031      * @throws SecurityException if the caller doesn't have required permission.
1032      *
1033      * @hide
1034      */
1035     @SystemApi
1036     @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
requestIsDemoModeEnabled(@onNull @allbackExecutor Executor executor, @NonNull OutcomeReceiver<Boolean, SatelliteException> callback)1037     public void requestIsDemoModeEnabled(@NonNull @CallbackExecutor Executor executor,
1038             @NonNull OutcomeReceiver<Boolean, SatelliteException> callback) {
1039         Objects.requireNonNull(executor);
1040         Objects.requireNonNull(callback);
1041 
1042         try {
1043             ITelephony telephony = getITelephony();
1044             if (telephony != null) {
1045                 ResultReceiver receiver = new ResultReceiver(null) {
1046                     @Override
1047                     protected void onReceiveResult(int resultCode, Bundle resultData) {
1048                         if (resultCode == SATELLITE_RESULT_SUCCESS) {
1049                             if (resultData.containsKey(KEY_DEMO_MODE_ENABLED)) {
1050                                 boolean isDemoModeEnabled =
1051                                         resultData.getBoolean(KEY_DEMO_MODE_ENABLED);
1052                                 executor.execute(() -> Binder.withCleanCallingIdentity(() ->
1053                                         callback.onResult(isDemoModeEnabled)));
1054                             } else {
1055                                 loge("KEY_DEMO_MODE_ENABLED does not exist.");
1056                                 executor.execute(() -> Binder.withCleanCallingIdentity(() ->
1057                                         callback.onError(new SatelliteException(
1058                                                 SATELLITE_RESULT_REQUEST_FAILED))));
1059                             }
1060                         } else {
1061                             executor.execute(() -> Binder.withCleanCallingIdentity(() ->
1062                                     callback.onError(new SatelliteException(resultCode))));
1063                         }
1064                     }
1065                 };
1066                 telephony.requestIsDemoModeEnabled(receiver);
1067             } else {
1068                 loge("requestIsDemoModeEnabled() invalid telephony");
1069                 executor.execute(() -> Binder.withCleanCallingIdentity(() -> callback.onError(
1070                         new SatelliteException(SATELLITE_RESULT_ILLEGAL_STATE))));
1071             }
1072         } catch (RemoteException ex) {
1073             loge("requestIsDemoModeEnabled() RemoteException: " + ex);
1074             executor.execute(() -> Binder.withCleanCallingIdentity(() -> callback.onError(
1075                     new SatelliteException(SATELLITE_RESULT_ILLEGAL_STATE))));
1076         }
1077     }
1078 
1079     /**
1080      * Request to get whether the satellite service is enabled for emergency mode.
1081      *
1082      * @param executor The executor on which the callback will be called.
1083      * @param callback The callback object to which the result will be delivered.
1084      *                 If the request is successful, {@link OutcomeReceiver#onResult(Object)}
1085      *                 will return a {@code boolean} with value {@code true} if satellite is enabled
1086      *                 for emergency mode and {@code false} otherwise.
1087      *                 If the request is not successful, {@link OutcomeReceiver#onError(Throwable)}
1088      *                 will return a {@link SatelliteException} with the {@link SatelliteResult}.
1089      *
1090      * @throws SecurityException if the caller doesn't have required permission.
1091      *
1092      * @hide
1093      */
1094     @SystemApi
1095     @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
requestIsEmergencyModeEnabled(@onNull @allbackExecutor Executor executor, @NonNull OutcomeReceiver<Boolean, SatelliteException> callback)1096     public void requestIsEmergencyModeEnabled(@NonNull @CallbackExecutor Executor executor,
1097             @NonNull OutcomeReceiver<Boolean, SatelliteException> callback) {
1098         Objects.requireNonNull(executor);
1099         Objects.requireNonNull(callback);
1100 
1101         try {
1102             ITelephony telephony = getITelephony();
1103             if (telephony != null) {
1104                 ResultReceiver receiver = new ResultReceiver(null) {
1105                     @Override
1106                     protected void onReceiveResult(int resultCode, Bundle resultData) {
1107                         if (resultCode == SATELLITE_RESULT_SUCCESS) {
1108                             if (resultData.containsKey(KEY_EMERGENCY_MODE_ENABLED)) {
1109                                 boolean isEmergencyModeEnabled =
1110                                         resultData.getBoolean(KEY_EMERGENCY_MODE_ENABLED);
1111                                 executor.execute(() -> Binder.withCleanCallingIdentity(() ->
1112                                         callback.onResult(isEmergencyModeEnabled)));
1113                             } else {
1114                                 loge("KEY_EMERGENCY_MODE_ENABLED does not exist.");
1115                                 executor.execute(() -> Binder.withCleanCallingIdentity(() ->
1116                                         callback.onError(new SatelliteException(
1117                                                 SATELLITE_RESULT_REQUEST_FAILED))));
1118                             }
1119                         } else {
1120                             executor.execute(() -> Binder.withCleanCallingIdentity(() ->
1121                                     callback.onError(new SatelliteException(resultCode))));
1122                         }
1123                     }
1124                 };
1125                 telephony.requestIsEmergencyModeEnabled(receiver);
1126             } else {
1127                 executor.execute(() -> Binder.withCleanCallingIdentity(() -> callback.onError(
1128                         new SatelliteException(SATELLITE_RESULT_ILLEGAL_STATE))));
1129             }
1130         } catch (RemoteException ex) {
1131             loge("requestIsEmergencyModeEnabled() RemoteException: " + ex);
1132             ex.rethrowAsRuntimeException();
1133         }
1134     }
1135 
1136     /**
1137      * Request to get whether the satellite service is supported on the device.
1138      *
1139      * <p>
1140      * Note: This API only checks whether the device supports the satellite feature. The result will
1141      * not be affected by whether the device is provisioned.
1142      * </p>
1143      *
1144      * @param executor The executor on which the callback will be called.
1145      * @param callback The callback object to which the result will be delivered.
1146      *                 If the request is successful, {@link OutcomeReceiver#onResult(Object)}
1147      *                 will return a {@code boolean} with value {@code true} if the satellite
1148      *                 service is supported on the device and {@code false} otherwise.
1149      *                 If the request is not successful, {@link OutcomeReceiver#onError(Throwable)}
1150      *                 will return a {@link SatelliteException} with the {@link SatelliteResult}.
1151      *
1152      * @hide
1153      */
1154     @SystemApi
requestIsSupported(@onNull @allbackExecutor Executor executor, @NonNull OutcomeReceiver<Boolean, SatelliteException> callback)1155     public void requestIsSupported(@NonNull @CallbackExecutor Executor executor,
1156             @NonNull OutcomeReceiver<Boolean, SatelliteException> callback) {
1157         Objects.requireNonNull(executor);
1158         Objects.requireNonNull(callback);
1159 
1160         try {
1161             ITelephony telephony = getITelephony();
1162             if (telephony != null) {
1163                 ResultReceiver receiver = new ResultReceiver(null) {
1164                     @Override
1165                     protected void onReceiveResult(int resultCode, Bundle resultData) {
1166                         if (resultCode == SATELLITE_RESULT_SUCCESS) {
1167                             if (resultData.containsKey(KEY_SATELLITE_SUPPORTED)) {
1168                                 boolean isSatelliteSupported =
1169                                         resultData.getBoolean(KEY_SATELLITE_SUPPORTED);
1170                                 executor.execute(() -> Binder.withCleanCallingIdentity(() ->
1171                                         callback.onResult(isSatelliteSupported)));
1172                             } else {
1173                                 loge("KEY_SATELLITE_SUPPORTED does not exist.");
1174                                 executor.execute(() -> Binder.withCleanCallingIdentity(() ->
1175                                         callback.onError(new SatelliteException(
1176                                                 SATELLITE_RESULT_REQUEST_FAILED))));
1177                             }
1178                         } else {
1179                             executor.execute(() -> Binder.withCleanCallingIdentity(() ->
1180                                     callback.onError(new SatelliteException(resultCode))));
1181                         }
1182                     }
1183                 };
1184                 telephony.requestIsSatelliteSupported(receiver);
1185             } else {
1186                 loge("requestIsSupported() invalid telephony");
1187                 executor.execute(() -> Binder.withCleanCallingIdentity(() -> callback.onError(
1188                         new SatelliteException(SATELLITE_RESULT_ILLEGAL_STATE))));
1189             }
1190         } catch (RemoteException ex) {
1191             loge("requestIsSupported() RemoteException: " + ex);
1192             executor.execute(() -> Binder.withCleanCallingIdentity(() -> callback.onError(
1193                     new SatelliteException(SATELLITE_RESULT_ILLEGAL_STATE))));
1194         }
1195     }
1196 
1197     /**
1198      * Request to get the {@link SatelliteCapabilities} of the satellite service.
1199      *
1200      * @param executor The executor on which the callback will be called.
1201      * @param callback The callback object to which the result will be delivered.
1202      *                 If the request is successful, {@link OutcomeReceiver#onResult(Object)}
1203      *                 will return the {@link SatelliteCapabilities} of the satellite service.
1204      *                 If the request is not successful, {@link OutcomeReceiver#onError(Throwable)}
1205      *                 will return a {@link SatelliteException} with the {@link SatelliteResult}.
1206      *
1207      * @throws SecurityException if the caller doesn't have required permission.
1208      *
1209      * @hide
1210      */
1211     @SystemApi
1212     @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
requestCapabilities(@onNull @allbackExecutor Executor executor, @NonNull OutcomeReceiver<SatelliteCapabilities, SatelliteException> callback)1213     public void requestCapabilities(@NonNull @CallbackExecutor Executor executor,
1214             @NonNull OutcomeReceiver<SatelliteCapabilities, SatelliteException> callback) {
1215         Objects.requireNonNull(executor);
1216         Objects.requireNonNull(callback);
1217 
1218         try {
1219             ITelephony telephony = getITelephony();
1220             if (telephony != null) {
1221                 ResultReceiver receiver = new ResultReceiver(null) {
1222                     @Override
1223                     protected void onReceiveResult(int resultCode, Bundle resultData) {
1224                         if (resultCode == SATELLITE_RESULT_SUCCESS) {
1225                             if (resultData.containsKey(KEY_SATELLITE_CAPABILITIES)) {
1226                                 SatelliteCapabilities capabilities =
1227                                         resultData.getParcelable(KEY_SATELLITE_CAPABILITIES,
1228                                                 SatelliteCapabilities.class);
1229                                 executor.execute(() -> Binder.withCleanCallingIdentity(() ->
1230                                         callback.onResult(capabilities)));
1231                             } else {
1232                                 loge("KEY_SATELLITE_CAPABILITIES does not exist.");
1233                                 executor.execute(() -> Binder.withCleanCallingIdentity(() ->
1234                                         callback.onError(new SatelliteException(
1235                                                 SATELLITE_RESULT_REQUEST_FAILED))));
1236                             }
1237                         } else {
1238                             executor.execute(() -> Binder.withCleanCallingIdentity(() ->
1239                                     callback.onError(new SatelliteException(resultCode))));
1240                         }
1241                     }
1242                 };
1243                 telephony.requestSatelliteCapabilities(receiver);
1244             } else {
1245                 loge("requestCapabilities() invalid telephony");
1246                 executor.execute(() -> Binder.withCleanCallingIdentity(() -> callback.onError(
1247                         new SatelliteException(SATELLITE_RESULT_ILLEGAL_STATE))));
1248             }
1249         } catch (RemoteException ex) {
1250             loge("requestCapabilities() RemoteException: " + ex);
1251             executor.execute(() -> Binder.withCleanCallingIdentity(() -> callback.onError(
1252                     new SatelliteException(SATELLITE_RESULT_ILLEGAL_STATE))));
1253         }
1254     }
1255 
1256     /**
1257      * The default state indicating that datagram transfer is idle.
1258      * This should be sent if there are no message transfer activity happening.
1259      * @hide
1260      */
1261     @SystemApi
1262     public static final int SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE = 0;
1263 
1264     /**
1265      * A transition state indicating that a datagram is being sent.
1266      * @hide
1267      */
1268     @SystemApi
1269     public static final int SATELLITE_DATAGRAM_TRANSFER_STATE_SENDING = 1;
1270 
1271     /**
1272      * An end state indicating that datagram sending completed successfully.
1273      * After datagram transfer completes, {@link #SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE}
1274      * will be sent if no more messages are pending.
1275      * @hide
1276      */
1277     @SystemApi
1278     public static final int SATELLITE_DATAGRAM_TRANSFER_STATE_SEND_SUCCESS = 2;
1279 
1280     /**
1281      * An end state indicating that datagram sending completed with a failure.
1282      * After datagram transfer completes, {@link #SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE}
1283      * must be sent before reporting any additional datagram transfer state changes. All pending
1284      * messages will be reported as failed, to the corresponding applications.
1285      * @hide
1286      */
1287     @SystemApi
1288     public static final int SATELLITE_DATAGRAM_TRANSFER_STATE_SEND_FAILED = 3;
1289 
1290     /**
1291      * A transition state indicating that a datagram is being received.
1292      * @hide
1293      */
1294     @SystemApi
1295     public static final int SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVING = 4;
1296 
1297     /**
1298      * An end state indicating that datagram receiving completed successfully.
1299      * After datagram transfer completes, {@link #SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE}
1300      * will be sent if no more messages are pending.
1301      * @hide
1302      */
1303     @SystemApi
1304     public static final int SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVE_SUCCESS = 5;
1305 
1306     /**
1307      * An end state indicating that datagram receive operation found that there are no
1308      * messages to be retrieved from the satellite.
1309      * After datagram transfer completes, {@link #SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE}
1310      * will be sent if no more messages are pending.
1311      * @hide
1312      */
1313     @SystemApi
1314     public static final int SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVE_NONE = 6;
1315 
1316     /**
1317      * An end state indicating that datagram receive completed with a failure.
1318      * After datagram transfer completes, {@link #SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE}
1319      * will be sent if no more messages are pending.
1320      * @hide
1321      */
1322     @SystemApi
1323     public static final int SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVE_FAILED = 7;
1324 
1325     /**
1326      * A transition state indicating that Telephony is waiting for satellite modem to connect to a
1327      * satellite network before sending a datagram or polling for datagrams. If the satellite modem
1328      * successfully connects to a satellite network, either
1329      * {@link #SATELLITE_DATAGRAM_TRANSFER_STATE_SENDING} or
1330      * {@link #SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVING} will be sent. Otherwise,
1331      * either {@link #SATELLITE_DATAGRAM_TRANSFER_STATE_SEND_FAILED} or
1332      * {@link #SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVE_FAILED} will be sent.
1333      * @hide
1334      */
1335     @SystemApi
1336     public static final int SATELLITE_DATAGRAM_TRANSFER_STATE_WAITING_TO_CONNECT = 8;
1337 
1338     /**
1339      * The datagram transfer state is unknown. This generic datagram transfer state should be used
1340      * only when the datagram transfer state cannot be mapped to other specific datagram transfer
1341      * states.
1342      * @hide
1343      */
1344     @SystemApi
1345     public static final int SATELLITE_DATAGRAM_TRANSFER_STATE_UNKNOWN = -1;
1346 
1347     /** @hide */
1348     @IntDef(prefix = {"SATELLITE_DATAGRAM_TRANSFER_STATE_"}, value = {
1349             SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE,
1350             SATELLITE_DATAGRAM_TRANSFER_STATE_SENDING,
1351             SATELLITE_DATAGRAM_TRANSFER_STATE_SEND_SUCCESS,
1352             SATELLITE_DATAGRAM_TRANSFER_STATE_SEND_FAILED,
1353             SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVING,
1354             SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVE_SUCCESS,
1355             SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVE_NONE,
1356             SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVE_FAILED,
1357             SATELLITE_DATAGRAM_TRANSFER_STATE_WAITING_TO_CONNECT,
1358             SATELLITE_DATAGRAM_TRANSFER_STATE_UNKNOWN
1359     })
1360     @Retention(RetentionPolicy.SOURCE)
1361     public @interface SatelliteDatagramTransferState {}
1362     // TODO: Split into two enums for sending and receiving states
1363 
1364     /**
1365      * Satellite modem is in idle state.
1366      * @hide
1367      */
1368     @SystemApi
1369     public static final int SATELLITE_MODEM_STATE_IDLE = 0;
1370 
1371     /**
1372      * Satellite modem is listening for incoming datagrams.
1373      * @hide
1374      */
1375     @SystemApi
1376     public static final int SATELLITE_MODEM_STATE_LISTENING = 1;
1377 
1378     /**
1379      * Satellite modem is sending and/or receiving datagrams.
1380      * @hide
1381      */
1382     @SystemApi
1383     public static final int SATELLITE_MODEM_STATE_DATAGRAM_TRANSFERRING = 2;
1384 
1385     /**
1386      * Satellite modem is retrying to send and/or receive datagrams.
1387      * @hide
1388      */
1389     @SystemApi
1390     public static final int SATELLITE_MODEM_STATE_DATAGRAM_RETRYING = 3;
1391 
1392     /**
1393      * Satellite modem is powered off.
1394      * @hide
1395      */
1396     @SystemApi
1397     public static final int SATELLITE_MODEM_STATE_OFF = 4;
1398 
1399     /**
1400      * Satellite modem is unavailable.
1401      * @hide
1402      */
1403     @SystemApi
1404     public static final int SATELLITE_MODEM_STATE_UNAVAILABLE = 5;
1405 
1406     /**
1407      * The satellite modem is powered on but the device is not registered to a satellite cell.
1408      * @hide
1409      */
1410     @SystemApi
1411     public static final int SATELLITE_MODEM_STATE_NOT_CONNECTED = 6;
1412 
1413     /**
1414      * The satellite modem is powered on and the device is registered to a satellite cell.
1415      * @hide
1416      */
1417     @SystemApi
1418     public static final int SATELLITE_MODEM_STATE_CONNECTED = 7;
1419 
1420     /**
1421      * The satellite modem is being powered on.
1422      * @hide
1423      */
1424     @SystemApi
1425     @FlaggedApi(Flags.FLAG_SATELLITE_SYSTEM_APIS)
1426     public static final int SATELLITE_MODEM_STATE_ENABLING_SATELLITE = 8;
1427 
1428     /**
1429      * The satellite modem is being powered off.
1430      * @hide
1431      */
1432     @SystemApi
1433     @FlaggedApi(Flags.FLAG_SATELLITE_SYSTEM_APIS)
1434     public static final int SATELLITE_MODEM_STATE_DISABLING_SATELLITE = 9;
1435 
1436     /**
1437      * Satellite modem state is unknown. This generic modem state should be used only when the
1438      * modem state cannot be mapped to other specific modem states.
1439      * @hide
1440      */
1441     @SystemApi
1442     public static final int SATELLITE_MODEM_STATE_UNKNOWN = -1;
1443 
1444     /** @hide */
1445     @IntDef(prefix = {"SATELLITE_MODEM_STATE_"}, value = {
1446             SATELLITE_MODEM_STATE_IDLE,
1447             SATELLITE_MODEM_STATE_LISTENING,
1448             SATELLITE_MODEM_STATE_DATAGRAM_TRANSFERRING,
1449             SATELLITE_MODEM_STATE_DATAGRAM_RETRYING,
1450             SATELLITE_MODEM_STATE_OFF,
1451             SATELLITE_MODEM_STATE_UNAVAILABLE,
1452             SATELLITE_MODEM_STATE_NOT_CONNECTED,
1453             SATELLITE_MODEM_STATE_CONNECTED,
1454             SATELLITE_MODEM_STATE_ENABLING_SATELLITE,
1455             SATELLITE_MODEM_STATE_DISABLING_SATELLITE,
1456             SATELLITE_MODEM_STATE_UNKNOWN
1457     })
1458     @Retention(RetentionPolicy.SOURCE)
1459     public @interface SatelliteModemState {}
1460 
1461     /**
1462      * Datagram type is unknown. This generic datagram type should be used only when the
1463      * datagram type cannot be mapped to other specific datagram types.
1464      * @hide
1465      */
1466     @SystemApi
1467     public static final int DATAGRAM_TYPE_UNKNOWN = 0;
1468 
1469     /**
1470      * Datagram type indicating that the datagram to be sent or received is of type SOS message.
1471      * @hide
1472      */
1473     @SystemApi
1474     public static final int DATAGRAM_TYPE_SOS_MESSAGE = 1;
1475 
1476     /**
1477      * Datagram type indicating that the datagram to be sent or received is of type
1478      * location sharing.
1479      * @hide
1480      */
1481     @SystemApi
1482     public static final int DATAGRAM_TYPE_LOCATION_SHARING = 2;
1483 
1484     /**
1485      * This type of datagram is used to keep the device in satellite connected state or check if
1486      * there is any incoming message.
1487      * @hide
1488      */
1489     @SystemApi
1490     @FlaggedApi(Flags.FLAG_SATELLITE_SYSTEM_APIS)
1491     public static final int DATAGRAM_TYPE_KEEP_ALIVE = 3;
1492 
1493     /**
1494      * Datagram type indicating that the datagram to be sent or received is of type SOS message and
1495      * is the last message to emergency service provider indicating still needs help.
1496      * @hide
1497      */
1498     @SystemApi
1499     @FlaggedApi(Flags.FLAG_SATELLITE_SYSTEM_APIS)
1500     public static final int DATAGRAM_TYPE_LAST_SOS_MESSAGE_STILL_NEED_HELP = 4;
1501 
1502     /**
1503      * Datagram type indicating that the datagram to be sent or received is of type SOS message and
1504      * is the last message to emergency service provider indicating no more help is needed.
1505      * @hide
1506      */
1507     @SystemApi
1508     @FlaggedApi(Flags.FLAG_SATELLITE_SYSTEM_APIS)
1509     public static final int DATAGRAM_TYPE_LAST_SOS_MESSAGE_NO_HELP_NEEDED = 5;
1510 
1511     /**
1512      * Datagram type indicating that the message to be sent or received is of type SMS.
1513      * @hide
1514      */
1515     @SystemApi
1516     @FlaggedApi(Flags.FLAG_SATELLITE_SYSTEM_APIS)
1517     public static final int DATAGRAM_TYPE_SMS = 6;
1518 
1519     /**
1520      * Datagram type indicating that the message to be sent is an SMS checking
1521      * for pending incoming SMS.
1522      * @hide
1523      */
1524     @SystemApi
1525     @FlaggedApi(Flags.FLAG_SATELLITE_SYSTEM_APIS)
1526     public static final int DATAGRAM_TYPE_CHECK_PENDING_INCOMING_SMS = 7;
1527 
1528     /** @hide */
1529     @IntDef(prefix = "DATAGRAM_TYPE_", value = {
1530             DATAGRAM_TYPE_UNKNOWN,
1531             DATAGRAM_TYPE_SOS_MESSAGE,
1532             DATAGRAM_TYPE_LOCATION_SHARING,
1533             DATAGRAM_TYPE_KEEP_ALIVE,
1534             DATAGRAM_TYPE_LAST_SOS_MESSAGE_STILL_NEED_HELP,
1535             DATAGRAM_TYPE_LAST_SOS_MESSAGE_NO_HELP_NEEDED,
1536             DATAGRAM_TYPE_SMS,
1537             DATAGRAM_TYPE_CHECK_PENDING_INCOMING_SMS
1538     })
1539     @Retention(RetentionPolicy.SOURCE)
1540     public @interface DatagramType {}
1541 
1542     /**
1543      * Satellite communication restricted by user.
1544      * @hide
1545      */
1546     @SystemApi
1547     @FlaggedApi(Flags.FLAG_SATELLITE_SYSTEM_APIS)
1548     public static final int SATELLITE_COMMUNICATION_RESTRICTION_REASON_USER = 0;
1549 
1550     /**
1551      * Satellite communication restricted by geolocation. This can be
1552      * triggered based upon geofence input provided by carrier to enable or disable satellite.
1553      * @hide
1554      */
1555     @SystemApi
1556     public static final int SATELLITE_COMMUNICATION_RESTRICTION_REASON_GEOLOCATION = 1;
1557 
1558     /**
1559      * Satellite communication restricted by entitlement server. This can be triggered based on
1560      * the EntitlementStatus value received from the entitlement server to enable or disable
1561      * satellite.
1562      * @hide
1563      */
1564     @SystemApi
1565     public static final int SATELLITE_COMMUNICATION_RESTRICTION_REASON_ENTITLEMENT = 2;
1566 
1567     /** @hide */
1568     @IntDef(prefix = "SATELLITE_COMMUNICATION_RESTRICTION_REASON_", value = {
1569             SATELLITE_COMMUNICATION_RESTRICTION_REASON_USER,
1570             SATELLITE_COMMUNICATION_RESTRICTION_REASON_GEOLOCATION,
1571             SATELLITE_COMMUNICATION_RESTRICTION_REASON_ENTITLEMENT
1572     })
1573     @Retention(RetentionPolicy.SOURCE)
1574     public @interface SatelliteCommunicationRestrictionReason {}
1575 
1576     /**
1577      * Satellite is disallowed because it is not supported.
1578      * @hide
1579      */
1580     public static final int SATELLITE_DISALLOWED_REASON_NOT_SUPPORTED = 0;
1581 
1582     /**
1583      * Satellite is disallowed because it has not been provisioned.
1584      * @hide
1585      */
1586     public static final int SATELLITE_DISALLOWED_REASON_NOT_PROVISIONED = 1;
1587 
1588     /**
1589      * Satellite is disallowed because it is currently outside an allowed region.
1590      * @hide
1591      */
1592     public static final int SATELLITE_DISALLOWED_REASON_NOT_IN_ALLOWED_REGION = 2;
1593 
1594     /**
1595      * Satellite is disallowed because an unsupported default message application is being used.
1596      * @hide
1597      */
1598     public static final int SATELLITE_DISALLOWED_REASON_UNSUPPORTED_DEFAULT_MSG_APP = 3;
1599 
1600     /**
1601      * Satellite is disallowed because location settings have been disabled.
1602      * @hide
1603      */
1604     public static final int SATELLITE_DISALLOWED_REASON_LOCATION_DISABLED = 4;
1605 
1606     /** @hide */
1607     @IntDef(prefix = "SATELLITE_DISALLOWED_REASON_", value = {
1608             SATELLITE_DISALLOWED_REASON_NOT_SUPPORTED,
1609             SATELLITE_DISALLOWED_REASON_NOT_PROVISIONED,
1610             SATELLITE_DISALLOWED_REASON_NOT_IN_ALLOWED_REGION,
1611             SATELLITE_DISALLOWED_REASON_UNSUPPORTED_DEFAULT_MSG_APP,
1612             SATELLITE_DISALLOWED_REASON_LOCATION_DISABLED,
1613     })
1614     @Retention(RetentionPolicy.SOURCE)
1615     public @interface SatelliteDisallowedReason {}
1616 
1617     /**
1618      * Start receiving satellite transmission updates.
1619      * This can be called by the pointing UI when the user starts pointing to the satellite.
1620      * Modem should continue to report the pointing input as the device or satellite moves.
1621      * Satellite transmission updates are started only on {@link #SATELLITE_RESULT_SUCCESS}.
1622      * All other results indicate that this operation failed.
1623      * Once satellite transmission updates begin, position and datagram transfer state updates
1624      * will be sent through {@link SatelliteTransmissionUpdateCallback}.
1625      *
1626      * @param executor The executor on which the callback and error code listener will be called.
1627      * @param resultListener Listener for the {@link SatelliteResult} result of the operation.
1628      * @param callback The callback to notify of satellite transmission updates.
1629      *
1630      * @throws SecurityException if the caller doesn't have required permission.
1631      *
1632      * @hide
1633      */
1634     @SystemApi
1635     @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
1636     @SuppressWarnings("SamShouldBeLast")
startTransmissionUpdates(@onNull @allbackExecutor Executor executor, @SatelliteResult @NonNull Consumer<Integer> resultListener, @NonNull SatelliteTransmissionUpdateCallback callback)1637     public void startTransmissionUpdates(@NonNull @CallbackExecutor Executor executor,
1638             @SatelliteResult @NonNull Consumer<Integer> resultListener,
1639             @NonNull SatelliteTransmissionUpdateCallback callback) {
1640         Objects.requireNonNull(executor);
1641         Objects.requireNonNull(resultListener);
1642         Objects.requireNonNull(callback);
1643 
1644         try {
1645             ITelephony telephony = getITelephony();
1646             if (telephony != null) {
1647                 IIntegerConsumer errorCallback = new IIntegerConsumer.Stub() {
1648                     @Override
1649                     public void accept(int result) {
1650                         executor.execute(() -> Binder.withCleanCallingIdentity(
1651                                 () -> resultListener.accept(result)));
1652                     }
1653                 };
1654                 ISatelliteTransmissionUpdateCallback internalCallback =
1655                         new ISatelliteTransmissionUpdateCallback.Stub() {
1656 
1657                             @Override
1658                             public void onSatellitePositionChanged(PointingInfo pointingInfo) {
1659                                 executor.execute(() -> Binder.withCleanCallingIdentity(
1660                                         () -> callback.onSatellitePositionChanged(pointingInfo)));
1661                             }
1662 
1663                             @Override
1664                             public void onSendDatagramStateChanged(int datagramType, int state,
1665                                     int sendPendingCount, int errorCode) {
1666                                 executor.execute(() -> Binder.withCleanCallingIdentity(
1667                                         () -> callback.onSendDatagramStateChanged(datagramType,
1668                                                 state, sendPendingCount, errorCode)));
1669 
1670                                 // For backward compatibility
1671                                 executor.execute(() -> Binder.withCleanCallingIdentity(
1672                                         () -> callback.onSendDatagramStateChanged(
1673                                                 state, sendPendingCount, errorCode)));
1674                             }
1675 
1676                             @Override
1677                             public void onReceiveDatagramStateChanged(int state,
1678                                     int receivePendingCount, int errorCode) {
1679                                 executor.execute(() -> Binder.withCleanCallingIdentity(
1680                                         () -> callback.onReceiveDatagramStateChanged(
1681                                                 state, receivePendingCount, errorCode)));
1682                             }
1683 
1684                             @Override
1685                             public void onSendDatagramRequested(int datagramType) {
1686                                 executor.execute(() -> Binder.withCleanCallingIdentity(
1687                                         () -> callback.onSendDatagramRequested(datagramType)));
1688                             }
1689                         };
1690                 sSatelliteTransmissionUpdateCallbackMap.put(callback, internalCallback);
1691                 telephony.startSatelliteTransmissionUpdates(errorCallback, internalCallback);
1692             } else {
1693                 loge("startTransmissionUpdates() invalid telephony");
1694                 executor.execute(() -> Binder.withCleanCallingIdentity(
1695                         () -> resultListener.accept(SATELLITE_RESULT_ILLEGAL_STATE)));
1696             }
1697         } catch (RemoteException ex) {
1698             loge("startTransmissionUpdates() RemoteException: " + ex);
1699             executor.execute(() -> Binder.withCleanCallingIdentity(
1700                     () -> resultListener.accept(SATELLITE_RESULT_ILLEGAL_STATE)));
1701         }
1702     }
1703 
1704     /**
1705      * Stop receiving satellite transmission updates.
1706      * This can be called by the pointing UI when the user stops pointing to the satellite.
1707      * Satellite transmission updates are stopped and the callback is unregistered only on
1708      * {@link #SATELLITE_RESULT_SUCCESS}. All other results that this operation failed.
1709      *
1710      * @param callback The callback that was passed to {@link
1711      * #startTransmissionUpdates(Executor, Consumer, SatelliteTransmissionUpdateCallback)}.
1712      * @param executor The executor on which the error code listener will be called.
1713      * @param resultListener Listener for the {@link SatelliteResult} result of the operation.
1714      *
1715      * @throws SecurityException if the caller doesn't have required permission.
1716      *
1717      * @hide
1718      */
1719     @SystemApi
1720     @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
stopTransmissionUpdates(@onNull SatelliteTransmissionUpdateCallback callback, @SuppressWarnings("ListenerLast") @NonNull @CallbackExecutor Executor executor, @SuppressWarnings("ListenerLast") @SatelliteResult @NonNull Consumer<Integer> resultListener)1721     public void stopTransmissionUpdates(@NonNull SatelliteTransmissionUpdateCallback callback,
1722             @SuppressWarnings("ListenerLast") @NonNull @CallbackExecutor Executor executor,
1723             @SuppressWarnings("ListenerLast") @SatelliteResult @NonNull
1724             Consumer<Integer> resultListener) {
1725         Objects.requireNonNull(callback);
1726         Objects.requireNonNull(executor);
1727         Objects.requireNonNull(resultListener);
1728 
1729         ISatelliteTransmissionUpdateCallback internalCallback =
1730                 sSatelliteTransmissionUpdateCallbackMap.remove(callback);
1731 
1732         try {
1733             ITelephony telephony = getITelephony();
1734             if (telephony != null) {
1735                 if (internalCallback != null) {
1736                     IIntegerConsumer errorCallback = new IIntegerConsumer.Stub() {
1737                         @Override
1738                         public void accept(int result) {
1739                             executor.execute(() -> Binder.withCleanCallingIdentity(
1740                                     () -> resultListener.accept(result)));
1741                         }
1742                     };
1743                     telephony.stopSatelliteTransmissionUpdates(errorCallback, internalCallback);
1744                     // TODO: Notify SmsHandler that pointing UI stopped
1745                 } else {
1746                     loge("stopSatelliteTransmissionUpdates: No internal callback.");
1747                     executor.execute(() -> Binder.withCleanCallingIdentity(
1748                             () -> resultListener.accept(SATELLITE_RESULT_INVALID_ARGUMENTS)));
1749                 }
1750             } else {
1751                 loge("stopTransmissionUpdates() invalid telephony");
1752                 executor.execute(() -> Binder.withCleanCallingIdentity(
1753                         () -> resultListener.accept(SATELLITE_RESULT_ILLEGAL_STATE)));
1754             }
1755         } catch (RemoteException ex) {
1756             loge("stopTransmissionUpdates() RemoteException: " + ex);
1757             executor.execute(() -> Binder.withCleanCallingIdentity(
1758                     () -> resultListener.accept(SATELLITE_RESULT_ILLEGAL_STATE)));
1759         }
1760     }
1761 
1762     /**
1763      * Provision the device with a satellite provider.
1764      * This is needed if the provider allows dynamic registration.
1765      *
1766      * @param token The token is generated by the user which is used as a unique identifier for
1767      *              provisioning with satellite gateway.
1768      * @param provisionData Data from the provisioning app that can be used by provisioning server
1769      * @param cancellationSignal The optional signal used by the caller to cancel the provision
1770      *                           request. Even when the cancellation is signaled, Telephony will
1771      *                           still trigger the callback to return the result of this request.
1772      * @param executor The executor on which the error code listener will be called.
1773      * @param resultListener Listener for the {@link SatelliteResult} result of the operation.
1774      *
1775      * @throws SecurityException if the caller doesn't have required permission.
1776      *
1777      * @hide
1778      */
1779     @SystemApi
1780     @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
provisionService(@onNull String token, @NonNull byte[] provisionData, @Nullable CancellationSignal cancellationSignal, @NonNull @CallbackExecutor Executor executor, @SatelliteResult @NonNull Consumer<Integer> resultListener)1781     public void provisionService(@NonNull String token, @NonNull byte[] provisionData,
1782             @Nullable CancellationSignal cancellationSignal,
1783             @NonNull @CallbackExecutor Executor executor,
1784             @SatelliteResult @NonNull Consumer<Integer> resultListener) {
1785         Objects.requireNonNull(token);
1786         Objects.requireNonNull(executor);
1787         Objects.requireNonNull(resultListener);
1788         Objects.requireNonNull(provisionData);
1789 
1790         ICancellationSignal cancelRemote = null;
1791         try {
1792             ITelephony telephony = getITelephony();
1793             if (telephony != null) {
1794                 IIntegerConsumer errorCallback = new IIntegerConsumer.Stub() {
1795                     @Override
1796                     public void accept(int result) {
1797                         executor.execute(() -> Binder.withCleanCallingIdentity(
1798                                 () -> resultListener.accept(result)));
1799                     }
1800                 };
1801                 cancelRemote = telephony.provisionSatelliteService(token, provisionData,
1802                         errorCallback);
1803             } else {
1804                 loge("provisionService() invalid telephony");
1805                 executor.execute(() -> Binder.withCleanCallingIdentity(
1806                         () -> resultListener.accept(SATELLITE_RESULT_ILLEGAL_STATE)));
1807             }
1808         } catch (RemoteException ex) {
1809             loge("provisionService() RemoteException=" + ex);
1810             executor.execute(() -> Binder.withCleanCallingIdentity(
1811                     () -> resultListener.accept(SATELLITE_RESULT_ILLEGAL_STATE)));
1812         }
1813         if (cancellationSignal != null) {
1814             cancellationSignal.setRemote(cancelRemote);
1815         }
1816     }
1817 
1818     /**
1819      * Deprovision the device with the satellite provider.
1820      * This is needed if the provider allows dynamic registration. Once deprovisioned,
1821      * {@link SatelliteProvisionStateCallback#onSatelliteProvisionStateChanged(boolean)}
1822      * should report as deprovisioned.
1823      * For provisioning satellite service, refer to
1824      * {@link #provisionService(String, byte[], CancellationSignal, Executor, Consumer)}
1825      *
1826      * @param token The token of the device/subscription to be deprovisioned.
1827      *              This should match with the token passed as input in
1828      *              {@link #provisionService(String, byte[], CancellationSignal, Executor,
1829      *              Consumer)}
1830      * @param resultListener Listener for the {@link SatelliteResult} result of the operation.
1831      *
1832      * @throws SecurityException if the caller doesn't have required permission.
1833      *
1834      * @hide
1835      */
1836     @SystemApi
1837     @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
deprovisionService(@onNull String token, @NonNull @CallbackExecutor Executor executor, @SatelliteResult @NonNull Consumer<Integer> resultListener)1838     public void deprovisionService(@NonNull String token,
1839             @NonNull @CallbackExecutor Executor executor,
1840             @SatelliteResult @NonNull Consumer<Integer> resultListener) {
1841         Objects.requireNonNull(token);
1842         Objects.requireNonNull(executor);
1843         Objects.requireNonNull(resultListener);
1844 
1845         try {
1846             ITelephony telephony = getITelephony();
1847             if (telephony != null) {
1848                 IIntegerConsumer errorCallback = new IIntegerConsumer.Stub() {
1849                     @Override
1850                     public void accept(int result) {
1851                         executor.execute(() -> Binder.withCleanCallingIdentity(
1852                                 () -> resultListener.accept(result)));
1853                     }
1854                 };
1855                 telephony.deprovisionSatelliteService(token, errorCallback);
1856             } else {
1857                 loge("deprovisionService() invalid telephony");
1858                 executor.execute(() -> Binder.withCleanCallingIdentity(
1859                         () -> resultListener.accept(SATELLITE_RESULT_ILLEGAL_STATE)));
1860             }
1861         } catch (RemoteException ex) {
1862             loge("deprovisionService() RemoteException ex=" + ex);
1863             executor.execute(() -> Binder.withCleanCallingIdentity(
1864                     () -> resultListener.accept(SATELLITE_RESULT_ILLEGAL_STATE)));
1865         }
1866     }
1867 
1868     /**
1869      * Registers for the satellite provision state changed.
1870      *
1871      * @param executor The executor on which the callback will be called.
1872      * @param callback The callback to handle the satellite provision state changed event.
1873      *
1874      * @return The {@link SatelliteResult} result of the operation.
1875      *
1876      * @throws SecurityException if the caller doesn't have required permission.
1877      * @throws IllegalStateException if the Telephony process is not currently available.
1878      *
1879      * @hide
1880      */
1881     @SystemApi
1882     @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
registerForProvisionStateChanged( @onNull @allbackExecutor Executor executor, @NonNull SatelliteProvisionStateCallback callback)1883     @SatelliteResult public int registerForProvisionStateChanged(
1884             @NonNull @CallbackExecutor Executor executor,
1885             @NonNull SatelliteProvisionStateCallback callback) {
1886         Objects.requireNonNull(executor);
1887         Objects.requireNonNull(callback);
1888 
1889         try {
1890             ITelephony telephony = getITelephony();
1891             if (telephony != null) {
1892                 ISatelliteProvisionStateCallback internalCallback =
1893                         new ISatelliteProvisionStateCallback.Stub() {
1894                             @Override
1895                             public void onSatelliteProvisionStateChanged(boolean provisioned) {
1896                                 executor.execute(() -> Binder.withCleanCallingIdentity(
1897                                         () -> callback.onSatelliteProvisionStateChanged(
1898                                                 provisioned)));
1899                             }
1900 
1901                             @FlaggedApi(Flags.FLAG_CARRIER_ROAMING_NB_IOT_NTN)
1902                             @Override
1903                             public void onSatelliteSubscriptionProvisionStateChanged(
1904                                     @NonNull List<SatelliteSubscriberProvisionStatus>
1905                                             satelliteSubscriberProvisionStatus) {
1906                                 executor.execute(() -> Binder.withCleanCallingIdentity(() ->
1907                                         callback.onSatelliteSubscriptionProvisionStateChanged(
1908                                                 satelliteSubscriberProvisionStatus)));
1909                             }
1910                         };
1911                 sSatelliteProvisionStateCallbackMap.put(callback, internalCallback);
1912                 return telephony.registerForSatelliteProvisionStateChanged(internalCallback);
1913             } else {
1914                 throw new IllegalStateException("telephony service is null.");
1915             }
1916         } catch (RemoteException ex) {
1917             loge("registerForProvisionStateChanged() RemoteException: " + ex);
1918             ex.rethrowAsRuntimeException();
1919         }
1920         return SATELLITE_RESULT_REQUEST_FAILED;
1921     }
1922 
1923     /**
1924      * Unregisters for the satellite provision state changed.
1925      * If callback was not registered before, the request will be ignored.
1926      *
1927      * @param callback The callback that was passed to
1928      * {@link #registerForProvisionStateChanged(Executor, SatelliteProvisionStateCallback)}
1929      *
1930      * @throws SecurityException if the caller doesn't have required permission.
1931      * @throws IllegalStateException if the Telephony process is not currently available.
1932      *
1933      * @hide
1934      */
1935     @SystemApi
1936     @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
unregisterForProvisionStateChanged( @onNull SatelliteProvisionStateCallback callback)1937     public void unregisterForProvisionStateChanged(
1938             @NonNull SatelliteProvisionStateCallback callback) {
1939         Objects.requireNonNull(callback);
1940         ISatelliteProvisionStateCallback internalCallback =
1941                 sSatelliteProvisionStateCallbackMap.remove(callback);
1942 
1943         try {
1944             ITelephony telephony = getITelephony();
1945             if (telephony != null) {
1946                 if (internalCallback != null) {
1947                     telephony.unregisterForSatelliteProvisionStateChanged(internalCallback);
1948                 } else {
1949                     loge("unregisterForProvisionStateChanged: No internal callback.");
1950                 }
1951             } else {
1952                 throw new IllegalStateException("telephony service is null.");
1953             }
1954         } catch (RemoteException ex) {
1955             loge("unregisterForProvisionStateChanged() RemoteException: " + ex);
1956             ex.rethrowAsRuntimeException();
1957         }
1958     }
1959 
1960     /**
1961      * Request to get whether this device is provisioned with a satellite provider.
1962      *
1963      * @param executor The executor on which the callback will be called.
1964      * @param callback The callback object to which the result will be delivered.
1965      *                 If the request is successful, {@link OutcomeReceiver#onResult(Object)}
1966      *                 will return a {@code boolean} with value {@code true} if the device is
1967      *                 provisioned with a satellite provider and {@code false} otherwise.
1968      *                 If the request is not successful, {@link OutcomeReceiver#onError(Throwable)}
1969      *                 will return a {@link SatelliteException} with the {@link SatelliteResult}.
1970      *
1971      * @throws SecurityException if the caller doesn't have required permission.
1972      *
1973      * @hide
1974      */
1975     @SystemApi
1976     @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
requestIsProvisioned(@onNull @allbackExecutor Executor executor, @NonNull OutcomeReceiver<Boolean, SatelliteException> callback)1977     public void requestIsProvisioned(@NonNull @CallbackExecutor Executor executor,
1978             @NonNull OutcomeReceiver<Boolean, SatelliteException> callback) {
1979         Objects.requireNonNull(executor);
1980         Objects.requireNonNull(callback);
1981 
1982         try {
1983             ITelephony telephony = getITelephony();
1984             if (telephony != null) {
1985                 ResultReceiver receiver = new ResultReceiver(null) {
1986                     @Override
1987                     protected void onReceiveResult(int resultCode, Bundle resultData) {
1988                         if (resultCode == SATELLITE_RESULT_SUCCESS) {
1989                             if (resultData.containsKey(KEY_SATELLITE_PROVISIONED)) {
1990                                 boolean isSatelliteProvisioned =
1991                                         resultData.getBoolean(KEY_SATELLITE_PROVISIONED);
1992                                 executor.execute(() -> Binder.withCleanCallingIdentity(() ->
1993                                         callback.onResult(isSatelliteProvisioned)));
1994                             } else {
1995                                 loge("KEY_SATELLITE_PROVISIONED does not exist.");
1996                                 executor.execute(() -> Binder.withCleanCallingIdentity(() ->
1997                                         callback.onError(new SatelliteException(
1998                                                 SATELLITE_RESULT_REQUEST_FAILED))));
1999                             }
2000                         } else {
2001                             executor.execute(() -> Binder.withCleanCallingIdentity(() ->
2002                                     callback.onError(new SatelliteException(resultCode))));
2003                         }
2004                     }
2005                 };
2006                 telephony.requestIsSatelliteProvisioned(receiver);
2007             } else {
2008                 loge("requestIsProvisioned() invalid telephony");
2009                 executor.execute(() -> Binder.withCleanCallingIdentity(() -> callback.onError(
2010                         new SatelliteException(SATELLITE_RESULT_ILLEGAL_STATE))));
2011             }
2012         } catch (RemoteException ex) {
2013             loge("requestIsProvisioned() RemoteException: " + ex);
2014             executor.execute(() -> Binder.withCleanCallingIdentity(() -> callback.onError(
2015                     new SatelliteException(SATELLITE_RESULT_ILLEGAL_STATE))));
2016         }
2017     }
2018 
2019     /**
2020      * Registers for modem state changed from satellite modem.
2021      *
2022      * @param executor The executor on which the callback will be called.
2023      * @param callback The callback to handle the satellite modem state changed event.
2024      *
2025      * @return The {@link SatelliteResult} result of the operation.
2026      *
2027      * @throws SecurityException if the caller doesn't have required permission.
2028      * @throws IllegalStateException if the Telephony process is not currently available.
2029      *
2030      * @hide
2031      */
2032     @SystemApi
2033     @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
registerForModemStateChanged( @onNull @allbackExecutor Executor executor, @NonNull SatelliteModemStateCallback callback)2034     @SatelliteResult public int registerForModemStateChanged(
2035             @NonNull @CallbackExecutor Executor executor,
2036             @NonNull SatelliteModemStateCallback callback) {
2037         Objects.requireNonNull(executor);
2038         Objects.requireNonNull(callback);
2039 
2040         try {
2041             ITelephony telephony = getITelephony();
2042             if (telephony != null) {
2043                 ISatelliteModemStateCallback internalCallback =
2044                         new ISatelliteModemStateCallback.Stub() {
2045                     @Override
2046                     public void onSatelliteModemStateChanged(int state) {
2047                         executor.execute(() -> Binder.withCleanCallingIdentity(() ->
2048                                 callback.onSatelliteModemStateChanged(state)));
2049                     }
2050 
2051                     @Override
2052                     public void onEmergencyModeChanged(boolean isEmergency) {
2053                         executor.execute(() -> Binder.withCleanCallingIdentity(() ->
2054                                 callback.onEmergencyModeChanged(isEmergency)));
2055                     }
2056 
2057                     @Hide
2058                     @Override
2059                     public void onRegistrationFailure(int causeCode) {
2060                         executor.execute(() -> Binder.withCleanCallingIdentity(() ->
2061                                 callback.onRegistrationFailure(causeCode)));
2062                     }
2063 
2064                     @Override
2065                     public void onTerrestrialNetworkAvailableChanged(boolean isAvailable) {
2066                         executor.execute(() -> Binder.withCleanCallingIdentity(() ->
2067                                 callback.onTerrestrialNetworkAvailableChanged(isAvailable)));
2068                     }
2069                 };
2070                 sSatelliteModemStateCallbackMap.put(callback, internalCallback);
2071                 return telephony.registerForSatelliteModemStateChanged(internalCallback);
2072             } else {
2073                 throw new IllegalStateException("telephony service is null.");
2074             }
2075         } catch (RemoteException ex) {
2076             loge("registerForModemStateChanged() RemoteException:" + ex);
2077             ex.rethrowAsRuntimeException();
2078         }
2079         return SATELLITE_RESULT_REQUEST_FAILED;
2080     }
2081 
2082     /**
2083      * Unregisters for modem state changed from satellite modem.
2084      * If callback was not registered before, the request will be ignored.
2085      *
2086      * @param callback The callback that was passed to
2087      * {@link #registerForModemStateChanged(Executor, SatelliteModemStateCallback)}.
2088      *
2089      * @throws SecurityException if the caller doesn't have required permission.
2090      * @throws IllegalStateException if the Telephony process is not currently available.
2091      *
2092      * @hide
2093      */
2094     @SystemApi
2095     @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
unregisterForModemStateChanged( @onNull SatelliteModemStateCallback callback)2096     public void unregisterForModemStateChanged(
2097             @NonNull SatelliteModemStateCallback callback) {
2098         Objects.requireNonNull(callback);
2099         ISatelliteModemStateCallback internalCallback = sSatelliteModemStateCallbackMap.remove(
2100                 callback);
2101 
2102         try {
2103             ITelephony telephony = getITelephony();
2104             if (telephony != null) {
2105                 if (internalCallback != null) {
2106                     telephony.unregisterForModemStateChanged(internalCallback);
2107                 } else {
2108                     loge("unregisterForModemStateChanged: No internal callback.");
2109                 }
2110             } else {
2111                 throw new IllegalStateException("telephony service is null.");
2112             }
2113         } catch (RemoteException ex) {
2114             loge("unregisterForModemStateChanged() RemoteException:" + ex);
2115             ex.rethrowAsRuntimeException();
2116         }
2117     }
2118 
2119     /**
2120      * Register to receive incoming datagrams over satellite.
2121      *
2122      * To poll for pending satellite datagrams, refer to
2123      * {@link #pollPendingDatagrams(Executor, Consumer)}
2124      *
2125      * @param executor The executor on which the callback will be called.
2126      * @param callback The callback to handle incoming datagrams over satellite.
2127      *                 This callback with be invoked when a new datagram is received from satellite.
2128      *
2129      * @return The {@link SatelliteResult} result of the operation.
2130      *
2131      * @throws SecurityException if the caller doesn't have required permission.
2132      * @throws IllegalStateException if the Telephony process is not currently available.
2133      *
2134      * @hide
2135      */
2136     @SystemApi
2137     @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
registerForIncomingDatagram( @onNull @allbackExecutor Executor executor, @NonNull SatelliteDatagramCallback callback)2138     @SatelliteResult public int registerForIncomingDatagram(
2139             @NonNull @CallbackExecutor Executor executor,
2140             @NonNull SatelliteDatagramCallback callback) {
2141         Objects.requireNonNull(executor);
2142         Objects.requireNonNull(callback);
2143 
2144         try {
2145             ITelephony telephony = getITelephony();
2146             if (telephony != null) {
2147                 ISatelliteDatagramCallback internalCallback =
2148                         new ISatelliteDatagramCallback.Stub() {
2149                             @Override
2150                             public void onSatelliteDatagramReceived(long datagramId,
2151                                     @NonNull SatelliteDatagram datagram, int pendingCount,
2152                                     @NonNull IVoidConsumer internalAck) {
2153                                 Consumer<Void> externalAck = new Consumer<Void>() {
2154                                     @Override
2155                                     public void accept(Void result) {
2156                                         try {
2157                                             internalAck.accept();
2158                                         }  catch (RemoteException e) {
2159                                               logd("onSatelliteDatagramReceived "
2160                                                       + "RemoteException: " + e);
2161                                         }
2162                                     }
2163                                 };
2164 
2165                                 executor.execute(() -> Binder.withCleanCallingIdentity(
2166                                         () -> callback.onSatelliteDatagramReceived(
2167                                                 datagramId, datagram, pendingCount, externalAck)));
2168                             }
2169                         };
2170                 sSatelliteDatagramCallbackMap.put(callback, internalCallback);
2171                 return telephony.registerForIncomingDatagram(internalCallback);
2172             } else {
2173                 throw new IllegalStateException("telephony service is null.");
2174             }
2175         } catch (RemoteException ex) {
2176             loge("registerForIncomingDatagram() RemoteException:" + ex);
2177             ex.rethrowAsRuntimeException();
2178         }
2179         return SATELLITE_RESULT_REQUEST_FAILED;
2180     }
2181 
2182     /**
2183      * Unregister to stop receiving incoming datagrams over satellite.
2184      * If callback was not registered before, the request will be ignored.
2185      *
2186      * @param callback The callback that was passed to
2187      * {@link #registerForIncomingDatagram(Executor, SatelliteDatagramCallback)}.
2188      *
2189      * @throws SecurityException if the caller doesn't have required permission.
2190      * @throws IllegalStateException if the Telephony process is not currently available.
2191      *
2192      * @hide
2193      */
2194     @SystemApi
2195     @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
unregisterForIncomingDatagram(@onNull SatelliteDatagramCallback callback)2196     public void unregisterForIncomingDatagram(@NonNull SatelliteDatagramCallback callback) {
2197         Objects.requireNonNull(callback);
2198         ISatelliteDatagramCallback internalCallback =
2199                 sSatelliteDatagramCallbackMap.remove(callback);
2200 
2201         try {
2202             ITelephony telephony = getITelephony();
2203             if (telephony != null) {
2204                 if (internalCallback != null) {
2205                     telephony.unregisterForIncomingDatagram(internalCallback);
2206                 } else {
2207                     loge("unregisterForIncomingDatagram: No internal callback.");
2208                 }
2209             } else {
2210                 throw new IllegalStateException("telephony service is null.");
2211             }
2212         } catch (RemoteException ex) {
2213             loge("unregisterForIncomingDatagram() RemoteException:" + ex);
2214             ex.rethrowAsRuntimeException();
2215         }
2216     }
2217 
2218     /**
2219      * Poll pending satellite datagrams over satellite.
2220      *
2221      * This method should be called when user specifies to check incoming messages over satellite.
2222      * This method requests modem to check if there are any pending datagrams to be received over
2223      * satellite. If there are any incoming datagrams, they will be received via
2224      * {@link SatelliteDatagramCallback#onSatelliteDatagramReceived(long, SatelliteDatagram, int,
2225      * Consumer)} )}
2226      *
2227      * @param executor The executor on which the result listener will be called.
2228      * @param resultListener Listener for the {@link SatelliteResult} result of the operation.
2229      *
2230      * @throws SecurityException if the caller doesn't have required permission.
2231      *
2232      * @hide
2233      */
2234     @SystemApi
2235     @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
pollPendingDatagrams(@onNull @allbackExecutor Executor executor, @SatelliteResult @NonNull Consumer<Integer> resultListener)2236     public void pollPendingDatagrams(@NonNull @CallbackExecutor Executor executor,
2237             @SatelliteResult @NonNull Consumer<Integer> resultListener) {
2238         Objects.requireNonNull(executor);
2239         Objects.requireNonNull(resultListener);
2240 
2241         try {
2242             ITelephony telephony = getITelephony();
2243             if (telephony != null) {
2244                 IIntegerConsumer internalCallback = new IIntegerConsumer.Stub() {
2245                     @Override
2246                     public void accept(int result) {
2247                         executor.execute(() -> Binder.withCleanCallingIdentity(
2248                                 () -> resultListener.accept(result)));
2249                     }
2250                 };
2251                 telephony.pollPendingDatagrams(internalCallback);
2252             } else {
2253                 loge("pollPendingDatagrams() invalid telephony");
2254                 executor.execute(() -> Binder.withCleanCallingIdentity(
2255                         () -> resultListener.accept(SATELLITE_RESULT_ILLEGAL_STATE)));
2256             }
2257         } catch (RemoteException ex) {
2258             loge("pollPendingDatagrams() RemoteException:" + ex);
2259             executor.execute(() -> Binder.withCleanCallingIdentity(
2260                     () -> resultListener.accept(SATELLITE_RESULT_ILLEGAL_STATE)));
2261         }
2262     }
2263 
2264     /**
2265      * Send datagram over satellite.
2266      *
2267      * Gateway encodes SOS message or location sharing message into a datagram and passes it as
2268      * input to this method. Datagram received here will be passed down to modem without any
2269      * encoding or encryption.
2270      *
2271      * @param datagramType datagram type indicating whether the datagram is of type
2272      *                     SOS_SMS or LOCATION_SHARING.
2273      * @param datagram encoded gateway datagram which is encrypted by the caller.
2274      *                 Datagram will be passed down to modem without any encoding or encryption.
2275      * @param needFullScreenPointingUI If set to true, this indicates pointingUI app to open in full
2276      *                                 screen mode if satellite communication needs pointingUI.
2277      *                                 If this is set to false, pointingUI may be presented to the
2278      *                                 user in collapsed view. Application may decide to mark this
2279      *                                 flag as true when the user is sending data for the first time
2280      *                                 or whenever there is a considerable idle time between
2281      *                                 satellite activity. This decision should be done based upon
2282      *                                 user activity and the application's ability to determine the
2283      *                                 best possible UX experience for the user.
2284      * @param executor The executor on which the result listener will be called.
2285      * @param resultListener Listener for the {@link SatelliteResult} result of the operation.
2286      *
2287      * @throws SecurityException if the caller doesn't have required permission.
2288      *
2289      * @hide
2290      */
2291     @SystemApi
2292     @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
sendDatagram(@atagramType int datagramType, @NonNull SatelliteDatagram datagram, boolean needFullScreenPointingUI, @NonNull @CallbackExecutor Executor executor, @SatelliteResult @NonNull Consumer<Integer> resultListener)2293     public void sendDatagram(@DatagramType int datagramType,
2294             @NonNull SatelliteDatagram datagram, boolean needFullScreenPointingUI,
2295             @NonNull @CallbackExecutor Executor executor,
2296             @SatelliteResult @NonNull Consumer<Integer> resultListener) {
2297         Objects.requireNonNull(datagram);
2298         Objects.requireNonNull(executor);
2299         Objects.requireNonNull(resultListener);
2300 
2301         try {
2302             ITelephony telephony = getITelephony();
2303             if (telephony != null) {
2304                 IIntegerConsumer internalCallback = new IIntegerConsumer.Stub() {
2305                     @Override
2306                     public void accept(int result) {
2307                         executor.execute(() -> Binder.withCleanCallingIdentity(
2308                                 () -> resultListener.accept(result)));
2309                     }
2310                 };
2311                 telephony.sendDatagram(datagramType, datagram,
2312                         needFullScreenPointingUI, internalCallback);
2313             } else {
2314                 loge("sendDatagram() invalid telephony");
2315                 executor.execute(() -> Binder.withCleanCallingIdentity(
2316                         () -> resultListener.accept(SATELLITE_RESULT_ILLEGAL_STATE)));
2317             }
2318         } catch (RemoteException ex) {
2319             loge("sendDatagram() RemoteException:" + ex);
2320             executor.execute(() -> Binder.withCleanCallingIdentity(
2321                     () -> resultListener.accept(SATELLITE_RESULT_ILLEGAL_STATE)));
2322         }
2323     }
2324 
2325     /**
2326      * Request to get whether satellite communication is allowed for the current location.
2327      *
2328      * @param executor The executor on which the callback will be called.
2329      * @param callback The callback object to which the result will be delivered.
2330      *                 If the request is successful, {@link OutcomeReceiver#onResult(Object)}
2331      *                 will return a {@code boolean} with value {@code true} if satellite
2332      *                 communication is allowed for the current location and
2333      *                 {@code false} otherwise.
2334      *                 If the request is not successful, {@link OutcomeReceiver#onError(Throwable)}
2335      *                 will return a {@link SatelliteException} with the {@link SatelliteResult}.
2336      *
2337      * @throws SecurityException if the caller doesn't have required permission.
2338      *
2339      * @hide
2340      */
2341     @SystemApi
2342     @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
requestIsCommunicationAllowedForCurrentLocation( @onNull @allbackExecutor Executor executor, @NonNull OutcomeReceiver<Boolean, SatelliteException> callback)2343     public void requestIsCommunicationAllowedForCurrentLocation(
2344             @NonNull @CallbackExecutor Executor executor,
2345             @NonNull OutcomeReceiver<Boolean, SatelliteException> callback) {
2346         Objects.requireNonNull(executor);
2347         Objects.requireNonNull(callback);
2348 
2349         try {
2350             ITelephony telephony = getITelephony();
2351             if (telephony != null) {
2352                 ResultReceiver receiver = new ResultReceiver(null) {
2353                     @Override
2354                     protected void onReceiveResult(int resultCode, Bundle resultData) {
2355                         if (resultCode == SATELLITE_RESULT_SUCCESS) {
2356                             if (resultData.containsKey(KEY_SATELLITE_COMMUNICATION_ALLOWED)) {
2357                                 boolean isSatelliteCommunicationAllowed =
2358                                         resultData.getBoolean(KEY_SATELLITE_COMMUNICATION_ALLOWED);
2359                                 executor.execute(() -> Binder.withCleanCallingIdentity(() ->
2360                                         callback.onResult(isSatelliteCommunicationAllowed)));
2361                             } else {
2362                                 loge("KEY_SATELLITE_COMMUNICATION_ALLOWED does not exist.");
2363                                 executor.execute(() -> Binder.withCleanCallingIdentity(() ->
2364                                         callback.onError(new SatelliteException(
2365                                                 SATELLITE_RESULT_REQUEST_FAILED))));
2366                             }
2367                         } else {
2368                             executor.execute(() -> Binder.withCleanCallingIdentity(() ->
2369                                     callback.onError(new SatelliteException(resultCode))));
2370                         }
2371                     }
2372                 };
2373                 telephony.requestIsCommunicationAllowedForCurrentLocation(mSubId, receiver);
2374             } else {
2375                 loge("requestIsCommunicationAllowedForCurrentLocation() invalid telephony");
2376                 executor.execute(() -> Binder.withCleanCallingIdentity(() -> callback.onError(
2377                         new SatelliteException(SATELLITE_RESULT_ILLEGAL_STATE))));
2378             }
2379         } catch (RemoteException ex) {
2380             loge("requestIsCommunicationAllowedForCurrentLocation() RemoteException: " + ex);
2381             executor.execute(() -> Binder.withCleanCallingIdentity(() -> callback.onError(
2382                     new SatelliteException(SATELLITE_RESULT_ILLEGAL_STATE))));
2383         }
2384     }
2385 
2386     /**
2387      * Request to get satellite access configuration for the current location.
2388      *
2389      * @param executor The executor on which the callback will be called.
2390      * @param callback The callback object to which the result will be delivered.
2391      *                 If the request is successful, {@link OutcomeReceiver#onResult(Object)}
2392      *                 will return a {@code SatelliteAccessConfiguration} with value the regional
2393      *                 satellite access configuration at the current location.
2394      *                 If the request is not successful, {@link OutcomeReceiver#onError(Throwable)}
2395      *                 will return a {@link SatelliteException} with the {@link SatelliteResult}.
2396      *
2397      * @throws SecurityException if the caller doesn't have required permission.
2398      *
2399      * @hide
2400      */
2401     @SystemApi
2402     @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
2403     @FlaggedApi(Flags.FLAG_SATELLITE_SYSTEM_APIS)
requestSatelliteAccessConfigurationForCurrentLocation( @onNull @allbackExecutor Executor executor, @NonNull OutcomeReceiver<SatelliteAccessConfiguration, SatelliteException> callback)2404     public void requestSatelliteAccessConfigurationForCurrentLocation(
2405             @NonNull @CallbackExecutor Executor executor,
2406             @NonNull OutcomeReceiver<SatelliteAccessConfiguration, SatelliteException> callback) {
2407         Objects.requireNonNull(executor);
2408         Objects.requireNonNull(callback);
2409 
2410         try {
2411             ITelephony telephony = getITelephony();
2412             if (telephony != null) {
2413                 ResultReceiver receiver = new ResultReceiver(null) {
2414                     @Override
2415                     protected void onReceiveResult(int resultCode, Bundle resultData) {
2416                         if (resultCode == SATELLITE_RESULT_SUCCESS) {
2417                             if (resultData.containsKey(KEY_SATELLITE_ACCESS_CONFIGURATION)) {
2418                                 SatelliteAccessConfiguration satelliteAccessConfiguration =
2419                                         resultData.getParcelable(KEY_SATELLITE_ACCESS_CONFIGURATION,
2420                                                 SatelliteAccessConfiguration.class);
2421                                 executor.execute(() -> Binder.withCleanCallingIdentity(() ->
2422                                         callback.onResult(satelliteAccessConfiguration)));
2423                             } else {
2424                                 loge("KEY_SATELLITE_ACCESS_CONFIGURATION does not exist.");
2425                                 executor.execute(() -> Binder.withCleanCallingIdentity(() ->
2426                                         callback.onError(new SatelliteException(
2427                                                 SATELLITE_RESULT_REQUEST_FAILED))));
2428                             }
2429                         } else {
2430                             executor.execute(() -> Binder.withCleanCallingIdentity(() ->
2431                                     callback.onError(new SatelliteException(resultCode))));
2432                         }
2433                     }
2434                 };
2435                 telephony.requestSatelliteAccessConfigurationForCurrentLocation(receiver);
2436             } else {
2437                 loge("requestSatelliteAccessConfigurationForCurrentLocation() invalid telephony");
2438                 executor.execute(() -> Binder.withCleanCallingIdentity(() -> callback.onError(
2439                         new SatelliteException(SATELLITE_RESULT_ILLEGAL_STATE))));
2440             }
2441         } catch (RemoteException ex) {
2442             loge("requestSatelliteAccessConfigurationForCurrentLocation() RemoteException: "
2443                     + ex);
2444             executor.execute(() -> Binder.withCleanCallingIdentity(() -> callback.onError(
2445                     new SatelliteException(SATELLITE_RESULT_ILLEGAL_STATE))));
2446         }
2447     }
2448 
2449     /**
2450      * Request to get the duration in seconds after which the satellite will be visible.
2451      * This will be {@link Duration#ZERO} if the satellite is currently visible.
2452      *
2453      * @param executor The executor on which the callback will be called.
2454      * @param callback The callback object to which the result will be delivered.
2455      *                 If the request is successful, {@link OutcomeReceiver#onResult(Object)}
2456      *                 will return the time after which the satellite will be visible.
2457      *                 If the request is not successful, {@link OutcomeReceiver#onError(Throwable)}
2458      *                 will return a {@link SatelliteException} with the {@link SatelliteResult}.
2459      *
2460      * @throws SecurityException if the caller doesn't have required permission.
2461      *
2462      * @hide
2463      */
2464     @SystemApi
2465     @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
requestTimeForNextSatelliteVisibility(@onNull @allbackExecutor Executor executor, @NonNull OutcomeReceiver<Duration, SatelliteException> callback)2466     public void requestTimeForNextSatelliteVisibility(@NonNull @CallbackExecutor Executor executor,
2467             @NonNull OutcomeReceiver<Duration, SatelliteException> callback) {
2468         Objects.requireNonNull(executor);
2469         Objects.requireNonNull(callback);
2470 
2471         try {
2472             ITelephony telephony = getITelephony();
2473             if (telephony != null) {
2474                 ResultReceiver receiver = new ResultReceiver(null) {
2475                     @Override
2476                     protected void onReceiveResult(int resultCode, Bundle resultData) {
2477                         if (resultCode == SATELLITE_RESULT_SUCCESS) {
2478                             if (resultData.containsKey(KEY_SATELLITE_NEXT_VISIBILITY)) {
2479                                 int nextVisibilityDuration =
2480                                         resultData.getInt(KEY_SATELLITE_NEXT_VISIBILITY);
2481                                 executor.execute(() -> Binder.withCleanCallingIdentity(() ->
2482                                         callback.onResult(
2483                                                 Duration.ofSeconds(nextVisibilityDuration))));
2484                             } else {
2485                                 loge("KEY_SATELLITE_NEXT_VISIBILITY does not exist.");
2486                                 executor.execute(() -> Binder.withCleanCallingIdentity(() ->
2487                                         callback.onError(new SatelliteException(
2488                                                 SATELLITE_RESULT_REQUEST_FAILED))));
2489                             }
2490                         } else {
2491                             executor.execute(() -> Binder.withCleanCallingIdentity(() ->
2492                                     callback.onError(new SatelliteException(resultCode))));
2493                         }
2494                     }
2495                 };
2496                 telephony.requestTimeForNextSatelliteVisibility(receiver);
2497             } else {
2498                 loge("requestTimeForNextSatelliteVisibility() invalid telephony");
2499                 executor.execute(() -> Binder.withCleanCallingIdentity(() -> callback.onError(
2500                         new SatelliteException(SATELLITE_RESULT_ILLEGAL_STATE))));
2501             }
2502         } catch (RemoteException ex) {
2503             loge("requestTimeForNextSatelliteVisibility() RemoteException: " + ex);
2504             executor.execute(() -> Binder.withCleanCallingIdentity(() -> callback.onError(
2505                     new SatelliteException(SATELLITE_RESULT_ILLEGAL_STATE))));
2506         }
2507     }
2508 
2509     /**
2510      * Request to get the currently selected satellite subscription id as an {@link Integer}.
2511      *
2512      * @param executor The executor on which the callback will be called.
2513      * @param callback The callback object to which the result will be delivered.
2514      *                 If the request is successful, {@link OutcomeReceiver#onResult(Object)}
2515      *                 will return the selected NB IOT satellite subscription ID.
2516      *                 If the request is not successful, {@link OutcomeReceiver#onError(Throwable)}
2517      *                 will return a {@link SatelliteException} with the {@link SatelliteResult}.
2518      *
2519      * @throws SecurityException if the caller doesn't have required permission.
2520      *
2521      * @hide
2522      */
2523     @SystemApi
2524     @FlaggedApi(Flags.FLAG_SATELLITE_SYSTEM_APIS)
2525     @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
requestSelectedNbIotSatelliteSubscriptionId( @onNull @allbackExecutor Executor executor, @NonNull OutcomeReceiver<Integer, SatelliteException> callback)2526     public void requestSelectedNbIotSatelliteSubscriptionId(
2527             @NonNull @CallbackExecutor Executor executor,
2528             @NonNull OutcomeReceiver<Integer, SatelliteException> callback) {
2529         Objects.requireNonNull(executor);
2530         Objects.requireNonNull(callback);
2531 
2532         try {
2533             ITelephony telephony = getITelephony();
2534             if (telephony != null) {
2535                 ResultReceiver receiver = new ResultReceiver(null) {
2536                     @Override
2537                     protected void onReceiveResult(int resultCode, Bundle resultData) {
2538                         if (resultCode == SATELLITE_RESULT_SUCCESS) {
2539                             if (resultData
2540                                     .containsKey(KEY_SELECTED_NB_IOT_SATELLITE_SUBSCRIPTION_ID)) {
2541                                 int selectedSatelliteSubscriptionId =
2542                                         resultData
2543                                             .getInt(KEY_SELECTED_NB_IOT_SATELLITE_SUBSCRIPTION_ID);
2544                                 executor.execute(() -> Binder.withCleanCallingIdentity(() ->
2545                                         callback.onResult(selectedSatelliteSubscriptionId)));
2546                             } else {
2547                                 loge(
2548                                     "KEY_SELECTED_NB_IOT_SATELLITE_SUBSCRIPTION_ID does not exist."
2549                                     );
2550                                 executor.execute(() -> Binder.withCleanCallingIdentity(() ->
2551                                         callback.onError(new SatelliteException(
2552                                                 SATELLITE_RESULT_REQUEST_FAILED))));
2553                             }
2554                         } else {
2555                             executor.execute(() -> Binder.withCleanCallingIdentity(() ->
2556                                     callback.onError(new SatelliteException(resultCode))));
2557                         }
2558                     }
2559                 };
2560                 telephony.requestSelectedNbIotSatelliteSubscriptionId(receiver);
2561             } else {
2562                 loge("requestSelectedNbIotSatelliteSubscriptionId() invalid telephony");
2563                 executor.execute(() -> Binder.withCleanCallingIdentity(() -> callback.onError(
2564                         new SatelliteException(SATELLITE_RESULT_ILLEGAL_STATE))));
2565             }
2566         } catch (RemoteException ex) {
2567             loge("requestSelectedNbIotSatelliteSubscriptionId() RemoteException: " + ex);
2568             executor.execute(() -> Binder.withCleanCallingIdentity(() -> callback.onError(
2569                     new SatelliteException(SATELLITE_RESULT_ILLEGAL_STATE))));
2570         }
2571     }
2572 
2573     /**
2574      * Registers for selected satellite subscription changed event from the satellite service.
2575      *
2576      * @param executor The executor on which the callback will be called.
2577      * @param callback The callback to handle the selected satellite subscription changed event.
2578      *
2579      * @return The {@link SatelliteResult} result of the operation.
2580      *
2581      * @throws SecurityException if the caller doesn't have required permission.
2582      * @throws IllegalStateException if the Telephony process is not currently available.
2583      *
2584      * @hide
2585      */
2586     @SystemApi
2587     @FlaggedApi(Flags.FLAG_SATELLITE_SYSTEM_APIS)
2588     @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
registerForSelectedNbIotSatelliteSubscriptionChanged( @onNull @allbackExecutor Executor executor, @NonNull SelectedNbIotSatelliteSubscriptionCallback callback)2589     @SatelliteResult public int registerForSelectedNbIotSatelliteSubscriptionChanged(
2590             @NonNull @CallbackExecutor Executor executor,
2591             @NonNull SelectedNbIotSatelliteSubscriptionCallback callback) {
2592         Objects.requireNonNull(executor);
2593         Objects.requireNonNull(callback);
2594 
2595         try {
2596             ITelephony telephony = getITelephony();
2597             if (telephony != null) {
2598                 ISelectedNbIotSatelliteSubscriptionCallback internalCallback =
2599                         new ISelectedNbIotSatelliteSubscriptionCallback.Stub() {
2600                             @Override
2601                             public void onSelectedNbIotSatelliteSubscriptionChanged(
2602                                     int selectedSubId) {
2603                                 executor.execute(() -> Binder.withCleanCallingIdentity(
2604                                         () -> callback.onSelectedNbIotSatelliteSubscriptionChanged(
2605                                                 selectedSubId)));
2606                             }
2607                         };
2608                 sSelectedNbIotSatelliteSubscriptionCallbackMap.put(callback, internalCallback);
2609                 return telephony.registerForSelectedNbIotSatelliteSubscriptionChanged(
2610                         internalCallback);
2611             } else {
2612                 throw new IllegalStateException("Telephony service is null.");
2613             }
2614         } catch (RemoteException ex) {
2615             loge("registerForSelectedNbIotSatelliteSubscriptionChanged() RemoteException: " + ex);
2616             ex.rethrowFromSystemServer();
2617         }
2618         return SATELLITE_RESULT_REQUEST_FAILED;
2619     }
2620 
2621     /**
2622      * Unregisters for selected satellite subscription changed event from the satellite service. If
2623      * callback was not registered before, the request will be ignored.
2624      *
2625      * @param callback The callback that was passed to {@link
2626      *     #registerForSelectedNbIotSatelliteSubscriptionChanged(Executor,
2627      *     SelectedNbIotSatelliteSubscriptionCallback)}.
2628      *
2629      * @throws SecurityException if the caller doesn't have required permission.
2630      * @throws IllegalStateException if the Telephony process is not currently available.
2631      * @hide
2632      */
2633     @SystemApi
2634     @FlaggedApi(Flags.FLAG_SATELLITE_SYSTEM_APIS)
2635     @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
unregisterForSelectedNbIotSatelliteSubscriptionChanged( @onNull SelectedNbIotSatelliteSubscriptionCallback callback)2636     public void unregisterForSelectedNbIotSatelliteSubscriptionChanged(
2637             @NonNull SelectedNbIotSatelliteSubscriptionCallback callback) {
2638         Objects.requireNonNull(callback);
2639         ISelectedNbIotSatelliteSubscriptionCallback internalCallback =
2640                 sSelectedNbIotSatelliteSubscriptionCallbackMap.remove(callback);
2641 
2642         try {
2643             ITelephony telephony = getITelephony();
2644             if (telephony != null) {
2645                 if (internalCallback != null) {
2646                     telephony.unregisterForSelectedNbIotSatelliteSubscriptionChanged(
2647                             internalCallback);
2648                 } else {
2649                     loge("unregisterForSelectedNbIotSatelliteSubscriptionChanged: " +
2650                             "No internal callback.");
2651                 }
2652             } else {
2653                 throw new IllegalStateException("Telephony service is null.");
2654             }
2655         } catch (RemoteException ex) {
2656             loge("unregisterForSelectedNbIotSatelliteSubscriptionChanged() RemoteException: " +
2657                     ex);
2658             ex.rethrowFromSystemServer();
2659         }
2660     }
2661 
2662     /**
2663      * Inform whether the device is aligned with the satellite in both real and demo mode.
2664      *
2665      * In demo mode, framework will send datagram to modem only when device is aligned with
2666      * the satellite. This method helps framework to simulate the experience of sending datagram
2667      * over satellite.
2668      *
2669      * @param isAligned {code @true} Device is aligned with the satellite
2670      *                  {code @false} Device is not aligned with the satellite
2671      *
2672      * @throws SecurityException if the caller doesn't have required permission.
2673      * @throws IllegalStateException if the Telephony process is not currently available.
2674      *
2675      * @hide
2676      */
2677     @SystemApi
2678     @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
setDeviceAlignedWithSatellite(boolean isAligned)2679     public void setDeviceAlignedWithSatellite(boolean isAligned) {
2680         try {
2681             ITelephony telephony = getITelephony();
2682             if (telephony != null) {
2683                 telephony.setDeviceAlignedWithSatellite(isAligned);
2684             } else {
2685                 throw new IllegalStateException("telephony service is null.");
2686             }
2687         } catch (RemoteException ex) {
2688             loge("setDeviceAlignedWithSatellite() RemoteException:" + ex);
2689             ex.rethrowAsRuntimeException();
2690         }
2691     }
2692 
2693     /**
2694      * User request to enable or disable carrier supported satellite plmn scan and attach by modem.
2695      * <p>
2696      * This API should be called by only settings app to pass down the user input for
2697      * enabling/disabling satellite. This user input will be persisted across device reboots.
2698      * <p>
2699      * Satellite will be enabled only when the following conditions are met:
2700      * <ul>
2701      * <li>Users want to enable it.</li>
2702      * <li>There is no satellite communication restriction, which is added by
2703      * {@link #addAttachRestrictionForCarrier(int, int, Executor, Consumer)}</li>
2704      * <li>The carrier config {@link
2705      * CarrierConfigManager#KEY_SATELLITE_ATTACH_SUPPORTED_BOOL} is set to
2706      * {@code true}.</li>
2707      * </ul>
2708      *
2709      * @param subId The subscription ID of the carrier.
2710      * @param enableSatellite {@code true} to enable the satellite and {@code false} to disable.
2711      * @param executor The executor on which the error code listener will be called.
2712      * @param resultListener Listener for the {@link SatelliteResult} result of the operation.
2713      *
2714      * @throws SecurityException if the caller doesn't have required permission.
2715      * @throws IllegalArgumentException if the subscription is invalid.
2716      *
2717      * @hide
2718      */
2719     @SystemApi
2720     @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
requestAttachEnabledForCarrier(int subId, boolean enableSatellite, @NonNull @CallbackExecutor Executor executor, @SatelliteResult @NonNull Consumer<Integer> resultListener)2721     public void requestAttachEnabledForCarrier(int subId, boolean enableSatellite,
2722             @NonNull @CallbackExecutor Executor executor,
2723             @SatelliteResult @NonNull Consumer<Integer> resultListener) {
2724         Objects.requireNonNull(executor);
2725         Objects.requireNonNull(resultListener);
2726 
2727         if (enableSatellite) {
2728             removeAttachRestrictionForCarrier(subId,
2729                     SATELLITE_COMMUNICATION_RESTRICTION_REASON_USER, executor, resultListener);
2730         } else {
2731             addAttachRestrictionForCarrier(subId,
2732                     SATELLITE_COMMUNICATION_RESTRICTION_REASON_USER, executor, resultListener);
2733         }
2734     }
2735 
2736     /**
2737      * Request to get whether the carrier supported satellite plmn scan and attach by modem is
2738      * enabled by user.
2739      *
2740      * @param subId The subscription ID of the carrier.
2741      * @param executor The executor on which the callback will be called.
2742      * @param callback The callback object to which the result will be delivered.
2743      *                 If the request is successful, {@link OutcomeReceiver#onResult(Object)}
2744      *                 will return a {@code boolean} with value {@code true} if the satellite
2745      *                 is enabled and {@code false} otherwise.
2746      *                 If the request is not successful, {@link OutcomeReceiver#onError(Throwable)}
2747      *                 will return a {@link SatelliteException} with the {@link SatelliteResult}.
2748      *
2749      * @throws SecurityException if the caller doesn't have required permission.
2750      * @throws IllegalStateException if the Telephony process is not currently available.
2751      * @throws IllegalArgumentException if the subscription is invalid.
2752      *
2753      * @hide
2754      */
2755     @SystemApi
2756     @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
requestIsAttachEnabledForCarrier(int subId, @NonNull @CallbackExecutor Executor executor, @NonNull OutcomeReceiver<Boolean, SatelliteException> callback)2757     public void requestIsAttachEnabledForCarrier(int subId,
2758             @NonNull @CallbackExecutor Executor executor,
2759             @NonNull OutcomeReceiver<Boolean, SatelliteException> callback) {
2760         Objects.requireNonNull(executor);
2761         Objects.requireNonNull(callback);
2762 
2763         Set<Integer> restrictionReason = getAttachRestrictionReasonsForCarrier(subId);
2764         executor.execute(() -> callback.onResult(
2765                 !restrictionReason.contains(SATELLITE_COMMUNICATION_RESTRICTION_REASON_USER)));
2766     }
2767 
2768     /**
2769      * Add a restriction reason for disallowing carrier supported satellite plmn scan and attach
2770      * by modem.
2771      *
2772      * @param subId The subscription ID of the carrier.
2773      * @param reason Reason for disallowing satellite communication.
2774      * @param executor The executor on which the error code listener will be called.
2775      * @param resultListener Listener for the {@link SatelliteResult} result of the operation.
2776      *
2777      * @throws SecurityException if the caller doesn't have required permission.
2778      * @throws IllegalArgumentException if the subscription is invalid.
2779      *
2780      * @hide
2781      */
2782     @SystemApi
2783     @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
addAttachRestrictionForCarrier(int subId, @SatelliteCommunicationRestrictionReason int reason, @NonNull @CallbackExecutor Executor executor, @SatelliteResult @NonNull Consumer<Integer> resultListener)2784     public void addAttachRestrictionForCarrier(int subId,
2785             @SatelliteCommunicationRestrictionReason int reason,
2786             @NonNull @CallbackExecutor Executor executor,
2787             @SatelliteResult @NonNull Consumer<Integer> resultListener) {
2788         if (!SubscriptionManager.isValidSubscriptionId(subId)) {
2789             throw new IllegalArgumentException("Invalid subscription ID");
2790         }
2791 
2792         try {
2793             ITelephony telephony = getITelephony();
2794             if (telephony != null) {
2795                 IIntegerConsumer errorCallback = new IIntegerConsumer.Stub() {
2796                     @Override
2797                     public void accept(int result) {
2798                         executor.execute(() -> Binder.withCleanCallingIdentity(
2799                                 () -> resultListener.accept(result)));
2800                     }
2801                 };
2802                 telephony.addAttachRestrictionForCarrier(subId, reason, errorCallback);
2803             } else {
2804                 loge("addAttachRestrictionForCarrier() invalid telephony");
2805                 executor.execute(() -> Binder.withCleanCallingIdentity(
2806                         () -> resultListener.accept(SATELLITE_RESULT_ILLEGAL_STATE)));
2807             }
2808         } catch (RemoteException ex) {
2809             loge("addAttachRestrictionForCarrier() RemoteException:" + ex);
2810             executor.execute(() -> Binder.withCleanCallingIdentity(
2811                     () -> resultListener.accept(SATELLITE_RESULT_ILLEGAL_STATE)));
2812         }
2813     }
2814 
2815     /**
2816      * Remove a restriction reason for disallowing carrier supported satellite plmn scan and attach
2817      * by modem.
2818      *
2819      * @param subId The subscription ID of the carrier.
2820      * @param reason Reason for disallowing satellite communication.
2821      * @param executor The executor on which the error code listener will be called.
2822      * @param resultListener Listener for the {@link SatelliteResult} result of the operation.
2823      *
2824      * @throws SecurityException if the caller doesn't have required permission.
2825      * @throws IllegalArgumentException if the subscription is invalid.
2826      *
2827      * @hide
2828      */
2829     @SystemApi
2830     @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
removeAttachRestrictionForCarrier(int subId, @SatelliteCommunicationRestrictionReason int reason, @NonNull @CallbackExecutor Executor executor, @SatelliteResult @NonNull Consumer<Integer> resultListener)2831     public void removeAttachRestrictionForCarrier(int subId,
2832             @SatelliteCommunicationRestrictionReason int reason,
2833             @NonNull @CallbackExecutor Executor executor,
2834             @SatelliteResult @NonNull Consumer<Integer> resultListener) {
2835         if (!SubscriptionManager.isValidSubscriptionId(subId)) {
2836             throw new IllegalArgumentException("Invalid subscription ID");
2837         }
2838 
2839         try {
2840             ITelephony telephony = getITelephony();
2841             if (telephony != null) {
2842                 IIntegerConsumer errorCallback = new IIntegerConsumer.Stub() {
2843                     @Override
2844                     public void accept(int result) {
2845                         executor.execute(() -> Binder.withCleanCallingIdentity(
2846                                 () -> resultListener.accept(result)));
2847                     }
2848                 };
2849                 telephony.removeAttachRestrictionForCarrier(subId, reason, errorCallback);
2850             } else {
2851                 loge("removeAttachRestrictionForCarrier() invalid telephony");
2852                 executor.execute(() -> Binder.withCleanCallingIdentity(
2853                         () -> resultListener.accept(SATELLITE_RESULT_ILLEGAL_STATE)));
2854             }
2855         } catch (RemoteException ex) {
2856             loge("removeAttachRestrictionForCarrier() RemoteException:" + ex);
2857             executor.execute(() -> Binder.withCleanCallingIdentity(
2858                     () -> resultListener.accept(SATELLITE_RESULT_ILLEGAL_STATE)));
2859         }
2860     }
2861 
2862     /**
2863      * Get reasons for disallowing satellite attach, as requested by
2864      * {@link #addAttachRestrictionForCarrier(int, int, Executor, Consumer)}
2865      *
2866      * @param subId The subscription ID of the carrier.
2867      * @return Set of reasons for disallowing satellite communication.
2868      *
2869      * @throws SecurityException if the caller doesn't have required permission.
2870      * @throws IllegalStateException if the Telephony process is not currently available.
2871      * @throws IllegalArgumentException if the subscription is invalid.
2872      *
2873      * @hide
2874      */
2875     @SystemApi
2876     @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
2877     @SatelliteCommunicationRestrictionReason
getAttachRestrictionReasonsForCarrier(int subId)2878     @NonNull public Set<Integer> getAttachRestrictionReasonsForCarrier(int subId) {
2879         if (!SubscriptionManager.isValidSubscriptionId(subId)) {
2880             throw new IllegalArgumentException("Invalid subscription ID");
2881         }
2882 
2883         try {
2884             ITelephony telephony = getITelephony();
2885             if (telephony != null) {
2886                 int[] receivedArray =
2887                         telephony.getAttachRestrictionReasonsForCarrier(subId);
2888                 if (receivedArray.length == 0) {
2889                     logd("receivedArray is empty, create empty set");
2890                     return new HashSet<>();
2891                 } else {
2892                     return Arrays.stream(receivedArray).boxed().collect(Collectors.toSet());
2893                 }
2894             } else {
2895                 throw new IllegalStateException("Telephony service is null.");
2896             }
2897         } catch (RemoteException ex) {
2898             loge("getAttachRestrictionReasonsForCarrier() RemoteException: " + ex);
2899             ex.rethrowAsRuntimeException();
2900         }
2901         return new HashSet<>();
2902     }
2903 
2904     /**
2905      * Returns list of disallowed reasons of satellite.
2906      *
2907      * @return Integer array of disallowed reasons.
2908      *
2909      * @throws SecurityException     if caller doesn't have required permission.
2910      * @throws IllegalStateException if Telephony process isn't available.
2911      * @hide
2912      */
2913     @SystemApi
2914     @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
2915     @SatelliteDisallowedReason
2916     @FlaggedApi(Flags.FLAG_SATELLITE_SYSTEM_APIS)
2917     @NonNull
getSatelliteDisallowedReasons()2918     public int[] getSatelliteDisallowedReasons() {
2919         try {
2920             ITelephony telephony = getITelephony();
2921             if (telephony != null) {
2922                 return telephony.getSatelliteDisallowedReasons();
2923             } else {
2924                 throw new IllegalStateException("Telephony service is null.");
2925             }
2926         } catch (RemoteException ex) {
2927             loge("getSatelliteDisallowedReasons() RemoteException: " + ex);
2928             ex.rethrowAsRuntimeException();
2929         }
2930         return new int[0];
2931     }
2932 
2933     /**
2934      * Registers for disallowed reasons change event from satellite service.
2935      *
2936      * @param executor The executor on which the callback will be called.
2937      * @param callback The callback to handle disallowed reasons changed event.
2938      *
2939      * @throws SecurityException     if caller doesn't have required permission.
2940      * @throws IllegalStateException if Telephony process is not available.
2941      * @hide
2942      */
2943     @SystemApi
2944     @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
2945     @FlaggedApi(Flags.FLAG_SATELLITE_SYSTEM_APIS)
registerForSatelliteDisallowedReasonsChanged( @onNull @allbackExecutor Executor executor, @NonNull SatelliteDisallowedReasonsCallback callback)2946     public void registerForSatelliteDisallowedReasonsChanged(
2947             @NonNull @CallbackExecutor Executor executor,
2948             @NonNull SatelliteDisallowedReasonsCallback callback) {
2949         Objects.requireNonNull(executor);
2950         Objects.requireNonNull(callback);
2951 
2952         try {
2953             ITelephony telephony = getITelephony();
2954             if (telephony != null) {
2955                 ISatelliteDisallowedReasonsCallback internalCallback =
2956                         new ISatelliteDisallowedReasonsCallback.Stub() {
2957                             @Override
2958                             public void onSatelliteDisallowedReasonsChanged(
2959                                     int[] disallowedReasons) {
2960                                 executor.execute(() -> Binder.withCleanCallingIdentity(
2961                                         () -> callback.onSatelliteDisallowedReasonsChanged(
2962                                                 disallowedReasons)));
2963                             }
2964                         };
2965                 telephony.registerForSatelliteDisallowedReasonsChanged(internalCallback);
2966                 sSatelliteDisallowedReasonsCallbackMap.put(callback, internalCallback);
2967             } else {
2968                 throw new IllegalStateException("Telephony service is null.");
2969             }
2970         } catch (RemoteException ex) {
2971             loge("registerForSatelliteDisallowedReasonsChanged() RemoteException" + ex);
2972             ex.rethrowAsRuntimeException();
2973         }
2974     }
2975 
2976     /**
2977      * Unregisters for disallowed reasons change event from satellite service.
2978      *
2979      * @param callback The callback that was passed to
2980      * {@link #registerForSatelliteDisallowedReasonsChanged(
2981      * Executor, SatelliteDisallowedReasonsCallback)}
2982      *
2983      * @throws SecurityException     if caller doesn't have required permission.
2984      * @throws IllegalStateException if Telephony process is not available.
2985      * @hide
2986      */
2987     @SystemApi
2988     @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
2989     @FlaggedApi(Flags.FLAG_SATELLITE_SYSTEM_APIS)
unregisterForSatelliteDisallowedReasonsChanged( @onNull SatelliteDisallowedReasonsCallback callback)2990     public void unregisterForSatelliteDisallowedReasonsChanged(
2991             @NonNull SatelliteDisallowedReasonsCallback callback) {
2992         Objects.requireNonNull(callback);
2993         ISatelliteDisallowedReasonsCallback internalCallback =
2994                 sSatelliteDisallowedReasonsCallbackMap.remove(callback);
2995 
2996         try {
2997             ITelephony telephony = getITelephony();
2998             if (telephony != null) {
2999                 if (internalCallback != null) {
3000                     telephony.unregisterForSatelliteDisallowedReasonsChanged(internalCallback);
3001                 } else {
3002                     loge("unregisterForSatelliteDisallowedReasonsChanged: No internal callback.");
3003                     throw new IllegalArgumentException("callback is not valid");
3004                 }
3005             } else {
3006                 throw new IllegalStateException("Telephony service is null.");
3007             }
3008         } catch (RemoteException ex) {
3009             loge("unregisterForSatelliteDisallowedReasonsChanged() RemoteException: " + ex);
3010             ex.rethrowAsRuntimeException();
3011         }
3012     }
3013 
3014     /**
3015      * Request to get the signal strength of the satellite connection.
3016      *
3017      * <p>
3018      * Note: This API is specifically designed for OEM enabled satellite connectivity only.
3019      * For satellite connectivity enabled using carrier roaming, please refer to
3020      * {@link TelephonyCallback.SignalStrengthsListener}, and
3021      * {@link TelephonyManager#registerTelephonyCallback(Executor, TelephonyCallback)}.
3022      * </p>
3023      *
3024      * @param executor The executor on which the callback will be called.
3025      * @param callback The callback object to which the result will be delivered. If the request is
3026      * successful, {@link OutcomeReceiver#onResult(Object)} will return an instance of
3027      * {@link NtnSignalStrength} with a value of {@link NtnSignalStrength.NtnSignalStrengthLevel}
3028      * The {@link NtnSignalStrength#NTN_SIGNAL_STRENGTH_NONE} will be returned if there is no
3029      * signal strength data available.
3030      * If the request is not successful, {@link OutcomeReceiver#onError(Throwable)} will return a
3031      * {@link SatelliteException} with the {@link SatelliteResult}.
3032      *
3033      * @throws SecurityException if the caller doesn't have required permission.
3034      *
3035      * @hide
3036      */
3037     @SystemApi
3038     @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
requestNtnSignalStrength(@onNull @allbackExecutor Executor executor, @NonNull OutcomeReceiver<NtnSignalStrength, SatelliteException> callback)3039     public void requestNtnSignalStrength(@NonNull @CallbackExecutor Executor executor,
3040             @NonNull OutcomeReceiver<NtnSignalStrength, SatelliteException> callback) {
3041         Objects.requireNonNull(executor);
3042         Objects.requireNonNull(callback);
3043 
3044         try {
3045             ITelephony telephony = getITelephony();
3046             if (telephony != null) {
3047                 ResultReceiver receiver = new ResultReceiver(null) {
3048                     @Override
3049                     protected void onReceiveResult(int resultCode, Bundle resultData) {
3050                         if (resultCode == SATELLITE_RESULT_SUCCESS) {
3051                             if (resultData.containsKey(KEY_NTN_SIGNAL_STRENGTH)) {
3052                                 NtnSignalStrength ntnSignalStrength =
3053                                         resultData.getParcelable(KEY_NTN_SIGNAL_STRENGTH,
3054                                                 NtnSignalStrength.class);
3055                                 executor.execute(() -> Binder.withCleanCallingIdentity(() ->
3056                                         callback.onResult(ntnSignalStrength)));
3057                             } else {
3058                                 loge("KEY_NTN_SIGNAL_STRENGTH does not exist.");
3059                                 executor.execute(() -> Binder.withCleanCallingIdentity(() ->
3060                                         callback.onError(new SatelliteException(
3061                                                 SATELLITE_RESULT_REQUEST_FAILED))));
3062                             }
3063                         } else {
3064                             executor.execute(() -> Binder.withCleanCallingIdentity(() ->
3065                                     callback.onError(new SatelliteException(resultCode))));
3066                         }
3067                     }
3068                 };
3069                 telephony.requestNtnSignalStrength(receiver);
3070             } else {
3071                 loge("requestNtnSignalStrength() invalid telephony");
3072                 executor.execute(() -> Binder.withCleanCallingIdentity(() -> callback.onError(
3073                         new SatelliteException(SATELLITE_RESULT_ILLEGAL_STATE))));
3074             }
3075         } catch (RemoteException ex) {
3076             loge("requestNtnSignalStrength() RemoteException: " + ex);
3077             executor.execute(() -> Binder.withCleanCallingIdentity(() -> callback.onError(
3078                     new SatelliteException(SATELLITE_RESULT_ILLEGAL_STATE))));
3079         }
3080     }
3081 
3082     /**
3083      * Registers for NTN signal strength changed from satellite modem.
3084      * If the registration operation is not successful, a {@link SatelliteException} that contains
3085      * {@link SatelliteResult} will be thrown.
3086      *
3087      * <p>
3088      * Note: This API is specifically designed for OEM enabled satellite connectivity only.
3089      * For satellite connectivity enabled using carrier roaming, please refer to
3090      * {@link TelephonyCallback.SignalStrengthsListener}, and
3091      * {@link TelephonyManager#registerTelephonyCallback(Executor, TelephonyCallback)}.
3092      * </p>
3093      *
3094      * @param executor The executor on which the callback will be called.
3095      * @param callback The callback to handle the NTN signal strength changed event.
3096      *
3097      * @throws SecurityException if the caller doesn't have required permission.
3098      * @throws IllegalStateException if the Telephony process is not currently available.
3099      *
3100      * @hide
3101      */
3102     @SystemApi
3103     @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
registerForNtnSignalStrengthChanged(@onNull @allbackExecutor Executor executor, @NonNull NtnSignalStrengthCallback callback)3104     public void registerForNtnSignalStrengthChanged(@NonNull @CallbackExecutor Executor executor,
3105             @NonNull NtnSignalStrengthCallback callback) {
3106         Objects.requireNonNull(executor);
3107         Objects.requireNonNull(callback);
3108 
3109         try {
3110             ITelephony telephony = getITelephony();
3111             if (telephony != null) {
3112                 INtnSignalStrengthCallback internalCallback =
3113                         new INtnSignalStrengthCallback.Stub() {
3114                             @Override
3115                             public void onNtnSignalStrengthChanged(
3116                                     NtnSignalStrength ntnSignalStrength) {
3117                                 executor.execute(() -> Binder.withCleanCallingIdentity(
3118                                         () -> callback.onNtnSignalStrengthChanged(
3119                                                 ntnSignalStrength)));
3120                             }
3121                         };
3122                 telephony.registerForNtnSignalStrengthChanged(internalCallback);
3123                 sNtnSignalStrengthCallbackMap.put(callback, internalCallback);
3124             } else {
3125                 throw new IllegalStateException("Telephony service is null.");
3126             }
3127         } catch (RemoteException ex) {
3128             loge("registerForNtnSignalStrengthChanged() RemoteException: " + ex);
3129             ex.rethrowAsRuntimeException();
3130         }
3131     }
3132 
3133     /**
3134      * Unregisters for NTN signal strength changed from satellite modem.
3135      * If callback was not registered before, the request will be ignored.
3136      *
3137      * <p>
3138      * Note: This API is specifically designed for OEM enabled satellite connectivity only.
3139      * For satellite connectivity enabled using carrier roaming, please refer to
3140      * {@link TelephonyManager#unregisterTelephonyCallback(TelephonyCallback)}..
3141      * </p>
3142      *
3143      * @param callback The callback that was passed to.
3144      * {@link #registerForNtnSignalStrengthChanged(Executor, NtnSignalStrengthCallback)}.
3145      *
3146      * @throws SecurityException if the caller doesn't have required permission.
3147      * @throws IllegalArgumentException if the callback is not valid or has already been
3148      * unregistered.
3149      * @throws IllegalStateException if the Telephony process is not currently available.
3150      *
3151      * @hide
3152      */
3153     @SystemApi
3154     @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
unregisterForNtnSignalStrengthChanged(@onNull NtnSignalStrengthCallback callback)3155     public void unregisterForNtnSignalStrengthChanged(@NonNull NtnSignalStrengthCallback callback) {
3156         Objects.requireNonNull(callback);
3157         INtnSignalStrengthCallback internalCallback =
3158                 sNtnSignalStrengthCallbackMap.remove(callback);
3159 
3160         try {
3161             ITelephony telephony = getITelephony();
3162             if (telephony != null) {
3163                 if (internalCallback != null) {
3164                     telephony.unregisterForNtnSignalStrengthChanged(internalCallback);
3165                 } else {
3166                     loge("unregisterForNtnSignalStrengthChanged: No internal callback.");
3167                     throw new IllegalArgumentException("callback is not valid");
3168                 }
3169             } else {
3170                 throw new IllegalStateException("Telephony service is null.");
3171             }
3172         } catch (RemoteException ex) {
3173             loge("unregisterForNtnSignalStrengthChanged() RemoteException: " + ex);
3174             ex.rethrowAsRuntimeException();
3175         }
3176     }
3177 
3178     /**
3179      * Registers for satellite capabilities change event from the satellite service.
3180      *
3181      * @param executor The executor on which the callback will be called.
3182      * @param callback The callback to handle the satellite capabilities changed event.
3183      *
3184      * @throws SecurityException if the caller doesn't have required permission.
3185      * @throws IllegalStateException if the Telephony process is not currently available.
3186      *
3187      * @hide
3188      */
3189     @SystemApi
3190     @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
registerForCapabilitiesChanged( @onNull @allbackExecutor Executor executor, @NonNull SatelliteCapabilitiesCallback callback)3191     @SatelliteResult public int registerForCapabilitiesChanged(
3192             @NonNull @CallbackExecutor Executor executor,
3193             @NonNull SatelliteCapabilitiesCallback callback) {
3194         Objects.requireNonNull(executor);
3195         Objects.requireNonNull(callback);
3196 
3197         try {
3198             ITelephony telephony = getITelephony();
3199             if (telephony != null) {
3200                 ISatelliteCapabilitiesCallback internalCallback =
3201                         new ISatelliteCapabilitiesCallback.Stub() {
3202                             @Override
3203                             public void onSatelliteCapabilitiesChanged(
3204                                     SatelliteCapabilities capabilities) {
3205                                 executor.execute(() -> Binder.withCleanCallingIdentity(
3206                                         () -> callback.onSatelliteCapabilitiesChanged(
3207                                                 capabilities)));
3208                             }
3209                         };
3210                 sSatelliteCapabilitiesCallbackMap.put(callback, internalCallback);
3211                 return telephony.registerForCapabilitiesChanged(internalCallback);
3212             } else {
3213                 throw new IllegalStateException("Telephony service is null.");
3214             }
3215         } catch (RemoteException ex) {
3216             loge("registerForCapabilitiesChanged() RemoteException: " + ex);
3217             ex.rethrowAsRuntimeException();
3218         }
3219         return SATELLITE_RESULT_REQUEST_FAILED;
3220     }
3221 
3222     /**
3223      * Unregisters for satellite capabilities change event from the satellite service.
3224      * If callback was not registered before, the request will be ignored.
3225      *
3226      * @param callback The callback that was passed to.
3227      * {@link #registerForCapabilitiesChanged(Executor, SatelliteCapabilitiesCallback)}.
3228      *
3229      * @throws SecurityException if the caller doesn't have required permission.
3230      * @throws IllegalStateException if the Telephony process is not currently available.
3231      *
3232      * @hide
3233      */
3234     @SystemApi
3235     @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
unregisterForCapabilitiesChanged( @onNull SatelliteCapabilitiesCallback callback)3236     public void unregisterForCapabilitiesChanged(
3237             @NonNull SatelliteCapabilitiesCallback callback) {
3238         Objects.requireNonNull(callback);
3239         ISatelliteCapabilitiesCallback internalCallback =
3240                 sSatelliteCapabilitiesCallbackMap.remove(callback);
3241 
3242         try {
3243             ITelephony telephony = getITelephony();
3244             if (telephony != null) {
3245                 if (internalCallback != null) {
3246                     telephony.unregisterForCapabilitiesChanged(internalCallback);
3247                 } else {
3248                     loge("unregisterForCapabilitiesChanged: No internal callback.");
3249                 }
3250             } else {
3251                 throw new IllegalStateException("Telephony service is null.");
3252             }
3253         } catch (RemoteException ex) {
3254             loge("unregisterForCapabilitiesChanged() RemoteException: " + ex);
3255             ex.rethrowAsRuntimeException();
3256         }
3257     }
3258 
3259     /**
3260      * Get all satellite PLMNs for which attach is enable for carrier.
3261      *
3262      * @param subId subId The subscription ID of the carrier.
3263      *
3264      * @return List of plmn for carrier satellite service. If no plmn is available, empty list will
3265      * be returned.
3266      *
3267      * @hide
3268      */
3269     @SystemApi
3270     @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
getSatellitePlmnsForCarrier(int subId)3271     @NonNull public List<String> getSatellitePlmnsForCarrier(int subId) {
3272         if (!SubscriptionManager.isValidSubscriptionId(subId)) {
3273             throw new IllegalArgumentException("Invalid subscription ID");
3274         }
3275 
3276         try {
3277             ITelephony telephony = getITelephony();
3278             if (telephony != null) {
3279                 return telephony.getSatellitePlmnsForCarrier(subId);
3280             } else {
3281                 throw new IllegalStateException("Telephony service is null.");
3282             }
3283         } catch (RemoteException ex) {
3284             loge("getSatellitePlmnsForCarrier() RemoteException: " + ex);
3285             ex.rethrowAsRuntimeException();
3286         }
3287         return new ArrayList<>();
3288     }
3289 
3290     /**
3291      * Registers for the satellite supported state changed.
3292      *
3293      * @param executor The executor on which the callback will be called.
3294      * @param callback The callback to handle the satellite supoprted state changed event.
3295      *
3296      * @return The result of the operation.
3297      *
3298      * @throws SecurityException if the caller doesn't have required permission.
3299      * @throws IllegalStateException if the Telephony process is not currently available.
3300      * @hide
3301      */
3302     @SystemApi
3303     @FlaggedApi(Flags.FLAG_SATELLITE_SYSTEM_APIS)
3304     @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
registerForSupportedStateChanged( @onNull @allbackExecutor Executor executor, @NonNull Consumer<Boolean> callback)3305     @SatelliteResult public int registerForSupportedStateChanged(
3306             @NonNull @CallbackExecutor Executor executor, @NonNull Consumer<Boolean> callback) {
3307         Objects.requireNonNull(executor);
3308         Objects.requireNonNull(callback);
3309 
3310         try {
3311             ITelephony telephony = getITelephony();
3312             if (telephony != null) {
3313                 IBooleanConsumer internalCallback = new IBooleanConsumer.Stub() {
3314                     @Override
3315                     public void accept(boolean supported) {
3316                         executor.execute(() -> Binder.withCleanCallingIdentity(
3317                                 () -> callback.accept(supported)));
3318                     }
3319                 };
3320                 sSatelliteSupportedStateCallbackMap.put(callback, internalCallback);
3321                 return telephony.registerForSatelliteSupportedStateChanged(
3322                         internalCallback);
3323             } else {
3324                 throw new IllegalStateException("telephony service is null.");
3325             }
3326         } catch (RemoteException ex) {
3327             loge("registerForSupportedStateChanged() RemoteException: " + ex);
3328             ex.rethrowAsRuntimeException();
3329         }
3330         return SATELLITE_RESULT_REQUEST_FAILED;
3331     }
3332 
3333     /**
3334      * Unregisters for the satellite supported state changed.
3335      * If callback was not registered before, the request will be ignored.
3336      *
3337      * @param callback The callback that was passed to
3338      * {@link #registerForSupportedStateChanged(Executor, Consumer)}
3339      *
3340      * @throws SecurityException if the caller doesn't have required permission.
3341      * @throws IllegalStateException if the Telephony process is not currently available.
3342      * @hide
3343      */
3344     @SystemApi
3345     @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
3346     @FlaggedApi(Flags.FLAG_SATELLITE_SYSTEM_APIS)
unregisterForSupportedStateChanged(@onNull Consumer<Boolean> callback)3347     public void unregisterForSupportedStateChanged(@NonNull Consumer<Boolean> callback) {
3348         Objects.requireNonNull(callback);
3349         IBooleanConsumer internalCallback =
3350                 sSatelliteSupportedStateCallbackMap.remove(callback);
3351 
3352         try {
3353             ITelephony telephony = getITelephony();
3354             if (telephony != null) {
3355                 if (internalCallback != null) {
3356                     telephony.unregisterForSatelliteSupportedStateChanged(internalCallback);
3357                 } else {
3358                     loge("unregisterForSupportedStateChanged: No internal callback.");
3359                 }
3360             } else {
3361                 throw new IllegalStateException("telephony service is null.");
3362             }
3363         } catch (RemoteException ex) {
3364             loge("unregisterForSupportedStateChanged() RemoteException: " + ex);
3365             ex.rethrowAsRuntimeException();
3366         }
3367     }
3368 
3369     /**
3370      * Registers for the satellite communication access state changed event.
3371      *
3372      * @param executor The executor on which the callback will be called.
3373      * @param callback The callback to handle satellite communication access state changed event.
3374      * @return The {@link SatelliteResult} result of the operation.
3375      * @throws SecurityException     if the caller doesn't have required permission.
3376      * @throws IllegalStateException if the Telephony process is not currently available.
3377      * @hide
3378      */
3379     @SystemApi
3380     @FlaggedApi(Flags.FLAG_SATELLITE_SYSTEM_APIS)
3381     @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
3382     @SatelliteResult
registerForCommunicationAccessStateChanged( @onNull @allbackExecutor Executor executor, @NonNull SatelliteCommunicationAccessStateCallback callback)3383     public int registerForCommunicationAccessStateChanged(
3384             @NonNull @CallbackExecutor Executor executor,
3385             @NonNull SatelliteCommunicationAccessStateCallback callback) {
3386         Objects.requireNonNull(executor);
3387         Objects.requireNonNull(callback);
3388 
3389         try {
3390             ITelephony telephony = getITelephony();
3391             if (telephony != null) {
3392                 ISatelliteCommunicationAccessStateCallback internalCallback =
3393                         new ISatelliteCommunicationAccessStateCallback.Stub() {
3394                             @Override
3395                             public void onAccessAllowedStateChanged(
3396                                     boolean isAllowed) {
3397                                 executor.execute(() -> Binder.withCleanCallingIdentity(
3398                                         () -> callback.onAccessAllowedStateChanged(
3399                                                 isAllowed)));
3400                             }
3401 
3402                             @Override
3403                             public void onAccessConfigurationChanged(
3404                                     @Nullable SatelliteAccessConfiguration
3405                                             satelliteAccessConfiguration) {
3406                                 executor.execute(() -> Binder.withCleanCallingIdentity(
3407                                         () -> callback.onAccessConfigurationChanged(
3408                                                 satelliteAccessConfiguration)));
3409                             }
3410                         };
3411                 sSatelliteCommunicationAccessStateCallbackMap.put(callback, internalCallback);
3412                 return telephony.registerForCommunicationAccessStateChanged(
3413                         mSubId, internalCallback);
3414             } else {
3415                 throw new IllegalStateException("telephony service is null.");
3416             }
3417         } catch (RemoteException ex) {
3418             loge("registerForCommunicationAccessStateChanged() RemoteException: " + ex);
3419             ex.rethrowAsRuntimeException();
3420         }
3421         return SATELLITE_RESULT_REQUEST_FAILED;
3422     }
3423 
3424     /**
3425      * Unregisters for the satellite communication access state changed event.
3426      * If callback was not registered before, the request will be ignored.
3427      *
3428      * @param callback The callback that was passed to
3429      *                 {@link #registerForCommunicationAccessStateChanged(Executor,
3430      *                 SatelliteCommunicationAccessStateCallback)}
3431      * @throws SecurityException     if the caller doesn't have required permission.
3432      * @throws IllegalStateException if the Telephony process is not currently available.
3433      * @hide
3434      */
3435     @SystemApi
3436     @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
3437     @FlaggedApi(Flags.FLAG_SATELLITE_SYSTEM_APIS)
unregisterForCommunicationAccessStateChanged( @onNull SatelliteCommunicationAccessStateCallback callback)3438     public void unregisterForCommunicationAccessStateChanged(
3439             @NonNull SatelliteCommunicationAccessStateCallback callback) {
3440         Objects.requireNonNull(callback);
3441         ISatelliteCommunicationAccessStateCallback internalCallback =
3442                 sSatelliteCommunicationAccessStateCallbackMap.remove(callback);
3443 
3444         try {
3445             ITelephony telephony = getITelephony();
3446             if (telephony != null) {
3447                 if (internalCallback != null) {
3448                     telephony.unregisterForCommunicationAccessStateChanged(mSubId,
3449                             internalCallback);
3450                 } else {
3451                     loge("unregisterForCommunicationAccessStateChanged: No internal callback.");
3452                 }
3453             } else {
3454                 throw new IllegalStateException("telephony service is null.");
3455             }
3456         } catch (RemoteException ex) {
3457             loge("unregisterForCommunicationAccessStateChanged() RemoteException: " + ex);
3458             ex.rethrowAsRuntimeException();
3459         }
3460     }
3461 
3462     /**
3463      * Request to get the {@link SatelliteSessionStats} of the satellite service.
3464      *
3465      * @param executor The executor on which the callback will be called.
3466      * @param callback The callback object to which the result will be delivered.
3467      *                 If the request is successful, {@link OutcomeReceiver#onResult(Object)}
3468      *                 will return the {@link SatelliteSessionStats} of the satellite service.
3469      *                 If the request is not successful, {@link OutcomeReceiver#onError(Throwable)}
3470      *                 will return a {@link SatelliteException} with the {@link SatelliteResult}.
3471      *
3472      * @throws SecurityException if the caller doesn't have required permission.
3473      * @hide
3474      */
3475     @RequiresPermission(allOf = {Manifest.permission.PACKAGE_USAGE_STATS,
3476             Manifest.permission.MODIFY_PHONE_STATE})
requestSessionStats(@onNull @allbackExecutor Executor executor, @NonNull OutcomeReceiver<SatelliteSessionStats, SatelliteException> callback)3477     public void requestSessionStats(@NonNull @CallbackExecutor Executor executor,
3478             @NonNull OutcomeReceiver<SatelliteSessionStats, SatelliteException> callback) {
3479         Objects.requireNonNull(executor);
3480         Objects.requireNonNull(callback);
3481 
3482         try {
3483             ITelephony telephony = getITelephony();
3484             if (telephony != null) {
3485                 ResultReceiver receiver = new ResultReceiver(null) {
3486                     @Override
3487                     protected void onReceiveResult(int resultCode, Bundle resultData) {
3488                         if (resultCode == SATELLITE_RESULT_SUCCESS) {
3489                             SatelliteSessionStats stats;
3490                             if (resultData.containsKey(KEY_SESSION_STATS)) {
3491                                 stats = resultData.getParcelable(KEY_SESSION_STATS,
3492                                         SatelliteSessionStats.class);
3493                                 if (resultData.containsKey(KEY_SESSION_STATS_V2)) {
3494                                     SatelliteSessionStats stats1 = resultData.getParcelable(
3495                                             KEY_SESSION_STATS_V2, SatelliteSessionStats.class);
3496                                     if (stats != null && stats1 != null) {
3497                                         stats.setSatelliteSessionStats(
3498                                                 stats1.getSatelliteSessionStats());
3499                                         executor.execute(() -> Binder.withCleanCallingIdentity(
3500                                                 () -> callback.onResult(stats)));
3501                                         return;
3502                                     }
3503                                 } else {
3504                                     loge("KEY_SESSION_STATS_V2 does not exist.");
3505                                 }
3506                             } else {
3507                                 loge("KEY_SESSION_STATS does not exist.");
3508                             }
3509                             executor.execute(() -> Binder.withCleanCallingIdentity(
3510                                     () -> callback.onError(new SatelliteException(
3511                                             SATELLITE_RESULT_REQUEST_FAILED))));
3512 
3513                         } else {
3514                             executor.execute(() -> Binder.withCleanCallingIdentity(
3515                                     () -> callback.onError(new SatelliteException(resultCode))));
3516                         }
3517                     }
3518                 };
3519                 telephony.requestSatelliteSessionStats(mSubId, receiver);
3520             } else {
3521                 loge("requestSessionStats() invalid telephony");
3522                 executor.execute(() -> Binder.withCleanCallingIdentity(() -> callback.onError(
3523                         new SatelliteException(SATELLITE_RESULT_ILLEGAL_STATE))));
3524             }
3525         } catch (RemoteException ex) {
3526             loge("requestSessionStats() RemoteException: " + ex);
3527             executor.execute(() -> Binder.withCleanCallingIdentity(() -> callback.onError(
3528                     new SatelliteException(SATELLITE_RESULT_ILLEGAL_STATE))));
3529         }
3530     }
3531 
3532     /**
3533      * Request to get list of prioritized satellite subscriber ids to be used for provision.
3534      *
3535      * Satellite Gateway client will use these subscriber ids to register with satellite gateway
3536      * service which identify user subscription with unique subscriber ids. These subscriber ids
3537      * can be any unique value like iccid, imsi or msisdn which is decided based upon carrier
3538      * requirements.
3539      *
3540      * @param executor The executor on which the callback will be called.
3541      * @param callback The callback object to which the result will be delivered.
3542      * If successful, the callback returns a list of tokens sorted in ascending priority order index
3543      * 0 has the highest priority. Otherwise, it returns an error with a SatelliteException.
3544      *
3545      * @throws SecurityException if the caller doesn't have required permission.
3546      * @hide
3547      */
3548     @SystemApi
3549     @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
3550     @FlaggedApi(Flags.FLAG_SATELLITE_SYSTEM_APIS)
requestSatelliteSubscriberProvisionStatus( @onNull @allbackExecutor Executor executor, @NonNull OutcomeReceiver<List<SatelliteSubscriberProvisionStatus>, SatelliteException> callback)3551     public void requestSatelliteSubscriberProvisionStatus(
3552             @NonNull @CallbackExecutor Executor executor,
3553             @NonNull OutcomeReceiver<List<SatelliteSubscriberProvisionStatus>,
3554                     SatelliteException> callback) {
3555         Objects.requireNonNull(executor);
3556         Objects.requireNonNull(callback);
3557 
3558         try {
3559             ITelephony telephony = getITelephony();
3560             if (telephony != null) {
3561                 ResultReceiver receiver = new ResultReceiver(null) {
3562                     @Override
3563                     protected void onReceiveResult(int resultCode, Bundle resultData) {
3564                         if (resultCode == SATELLITE_RESULT_SUCCESS) {
3565                             if (resultData.containsKey(KEY_REQUEST_PROVISION_SUBSCRIBER_ID_TOKEN)) {
3566                                 List<SatelliteSubscriberProvisionStatus> list =
3567                                         resultData.getParcelableArrayList(
3568                                                 KEY_REQUEST_PROVISION_SUBSCRIBER_ID_TOKEN,
3569                                                 SatelliteSubscriberProvisionStatus.class);
3570                                 executor.execute(() -> Binder.withCleanCallingIdentity(() ->
3571                                         callback.onResult(list)));
3572                             } else {
3573                                 loge("KEY_REQUEST_PROVISION_SUBSCRIBER_ID_TOKEN does not exist.");
3574                                 executor.execute(() -> Binder.withCleanCallingIdentity(() ->
3575                                         callback.onError(new SatelliteException(
3576                                                 SATELLITE_RESULT_REQUEST_FAILED))));
3577                             }
3578                         } else {
3579                             executor.execute(() -> Binder.withCleanCallingIdentity(() ->
3580                                     callback.onError(new SatelliteException(resultCode))));
3581                         }
3582                     }
3583                 };
3584                 telephony.requestSatelliteSubscriberProvisionStatus(receiver);
3585             } else {
3586                 loge("requestSatelliteSubscriberProvisionStatus() invalid telephony");
3587                 executor.execute(() -> Binder.withCleanCallingIdentity(() -> callback.onError(
3588                         new SatelliteException(SATELLITE_RESULT_ILLEGAL_STATE))));
3589             }
3590         } catch (RemoteException ex) {
3591             loge("requestSatelliteSubscriberProvisionStatus() RemoteException: " + ex);
3592             executor.execute(() -> Binder.withCleanCallingIdentity(() -> callback.onError(
3593                     new SatelliteException(SATELLITE_RESULT_ILLEGAL_STATE))));
3594         }
3595     }
3596 
3597     /**
3598      * Request to get the display name of satellite feature in the UI.
3599      *
3600      * @param executor The executor on which the callback will be called.
3601      * @param callback The callback object to which the result will be delivered.
3602      *                 If the request is successful, {@link OutcomeReceiver#onResult(Object)}
3603      *                 will return display name of the satellite feature in string format. Default
3604      *                 display name is "Satellite". If the request is not successful,
3605      *                 {@link OutcomeReceiver#onError(Throwable)} will return an error with
3606      *                 a SatelliteException.
3607      *
3608      * @throws SecurityException     if the caller doesn't have required permission.
3609      * @throws IllegalStateException if the Telephony process is not currently available.
3610      * @hide
3611      */
3612     @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
requestSatelliteDisplayName( @onNull @allbackExecutor Executor executor, @NonNull OutcomeReceiver<CharSequence, SatelliteException> callback)3613     public void requestSatelliteDisplayName(
3614             @NonNull @CallbackExecutor Executor executor,
3615             @NonNull OutcomeReceiver<CharSequence, SatelliteException> callback) {
3616         Objects.requireNonNull(executor);
3617         Objects.requireNonNull(callback);
3618 
3619         try {
3620             ITelephony telephony = getITelephony();
3621             if (telephony != null) {
3622                 ResultReceiver receiver = new ResultReceiver(null) {
3623                     @Override
3624                     protected void onReceiveResult(int resultCode, Bundle resultData) {
3625                         if (resultCode == SATELLITE_RESULT_SUCCESS) {
3626                             if (resultData.containsKey(KEY_SATELLITE_DISPLAY_NAME)) {
3627                                 CharSequence satelliteDisplayName =
3628                                         resultData.getString(KEY_SATELLITE_DISPLAY_NAME);
3629                                 executor.execute(() -> Binder.withCleanCallingIdentity(() ->
3630                                         callback.onResult(satelliteDisplayName)));
3631                             } else {
3632                                 loge("KEY_SATELLITE_DISPLAY_NAME does not exist.");
3633                                 executor.execute(() -> Binder.withCleanCallingIdentity(() ->
3634                                         callback.onError(new SatelliteException(
3635                                                 SATELLITE_RESULT_REQUEST_FAILED))));
3636                             }
3637                         } else {
3638                             executor.execute(() -> Binder.withCleanCallingIdentity(() ->
3639                                     callback.onError(new SatelliteException(resultCode))));
3640                         }
3641                     }
3642                 };
3643                 telephony.requestSatelliteDisplayName(receiver);
3644             } else {
3645                 loge("requestSatelliteDisplayName() invalid telephony");
3646                 executor.execute(() -> Binder.withCleanCallingIdentity(() -> callback.onError(
3647                         new SatelliteException(SATELLITE_RESULT_ILLEGAL_STATE))));
3648             }
3649         } catch (RemoteException ex) {
3650             loge("requestSatelliteDisplayName() RemoteException: " + ex);
3651             executor.execute(() -> Binder.withCleanCallingIdentity(() -> callback.onError(
3652                     new SatelliteException(SATELLITE_RESULT_ILLEGAL_STATE))));
3653         }
3654     }
3655 
3656     /**
3657      * Deliver the list of provisioned satellite subscriber infos.
3658      *
3659      * @param list The list of provisioned satellite subscriber infos.
3660      * @param executor The executor on which the callback will be called.
3661      * @param callback The callback object to which the result will be delivered.
3662      *                 If the request is successful, {@link OutcomeReceiver#onResult}
3663      *                 will be called.
3664      *                 If the request is not successful,
3665      *                 {@link OutcomeReceiver#onError(Throwable)} will return an error with
3666      *                 a SatelliteException.
3667      *
3668      * @throws SecurityException if the caller doesn't have required permission.
3669      * @hide
3670      */
3671     @SystemApi
3672     @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
3673     @FlaggedApi(Flags.FLAG_SATELLITE_SYSTEM_APIS)
provisionSatellite(@onNull List<SatelliteSubscriberInfo> list, @NonNull @CallbackExecutor Executor executor, @NonNull OutcomeReceiver<Void, SatelliteException> callback)3674     public void provisionSatellite(@NonNull List<SatelliteSubscriberInfo> list,
3675             @NonNull @CallbackExecutor Executor executor,
3676             @NonNull OutcomeReceiver<Void, SatelliteException> callback) {
3677         Objects.requireNonNull(executor);
3678         Objects.requireNonNull(callback);
3679 
3680         try {
3681             ITelephony telephony = getITelephony();
3682             if (telephony != null) {
3683                 ResultReceiver receiver = new ResultReceiver(null) {
3684                     @Override
3685                     protected void onReceiveResult(int resultCode, Bundle resultData) {
3686                         if (resultCode == SATELLITE_RESULT_SUCCESS) {
3687                             if (resultData.containsKey(KEY_PROVISION_SATELLITE_TOKENS)) {
3688                                 boolean isUpdated =
3689                                         resultData.getBoolean(KEY_PROVISION_SATELLITE_TOKENS);
3690                                 executor.execute(() -> Binder.withCleanCallingIdentity(
3691                                         () -> callback.onResult(null)));
3692                             } else {
3693                                 loge("KEY_REQUEST_PROVISION_TOKENS does not exist.");
3694                                 executor.execute(() -> Binder.withCleanCallingIdentity(() ->
3695                                         callback.onError(new SatelliteException(
3696                                                 SATELLITE_RESULT_REQUEST_FAILED))));
3697                             }
3698                         } else {
3699                             executor.execute(() -> Binder.withCleanCallingIdentity(() ->
3700                                     callback.onError(new SatelliteException(resultCode))));
3701                         }
3702                     }
3703                 };
3704                 telephony.provisionSatellite(list, receiver);
3705             } else {
3706                 loge("provisionSatellite() invalid telephony");
3707                 executor.execute(() -> Binder.withCleanCallingIdentity(() -> callback.onError(
3708                         new SatelliteException(SATELLITE_RESULT_ILLEGAL_STATE))));
3709             }
3710         } catch (RemoteException ex) {
3711             loge("provisionSatellite() RemoteException: " + ex);
3712             executor.execute(() -> Binder.withCleanCallingIdentity(() -> callback.onError(
3713                     new SatelliteException(SATELLITE_RESULT_ILLEGAL_STATE))));
3714         }
3715     }
3716 
3717     /**
3718      * Deliver the list of deprovisioned satellite subscriber infos.
3719      *
3720      * @param list The list of deprovisioned satellite subscriber infos.
3721      * @param executor The executor on which the callback will be called.
3722      * @param callback The callback object to which the result will be delivered.
3723      *                 If the request is successful, {@link OutcomeReceiver#onResult}
3724      *                 will be called.
3725      *                 If the request is not successful,
3726      *                 {@link OutcomeReceiver#onError(Throwable)} will return an error with
3727      *                 a SatelliteException.
3728      *
3729      * @throws SecurityException if the caller doesn't have required permission.
3730      * @hide
3731      */
3732     @SystemApi
3733     @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
3734     @FlaggedApi(Flags.FLAG_SATELLITE_SYSTEM_APIS)
deprovisionSatellite(@onNull List<SatelliteSubscriberInfo> list, @NonNull @CallbackExecutor Executor executor, @NonNull OutcomeReceiver<Void, SatelliteException> callback)3735     public void deprovisionSatellite(@NonNull List<SatelliteSubscriberInfo> list,
3736             @NonNull @CallbackExecutor Executor executor,
3737             @NonNull OutcomeReceiver<Void, SatelliteException> callback) {
3738         Objects.requireNonNull(executor);
3739         Objects.requireNonNull(callback);
3740 
3741         try {
3742             ITelephony telephony = getITelephony();
3743             if (telephony != null) {
3744                 ResultReceiver receiver = new ResultReceiver(null) {
3745                     @Override
3746                     protected void onReceiveResult(int resultCode, Bundle resultData) {
3747                         if (resultCode == SATELLITE_RESULT_SUCCESS) {
3748                             if (resultData.containsKey(KEY_DEPROVISION_SATELLITE_TOKENS)) {
3749                                 boolean isUpdated =
3750                                         resultData.getBoolean(KEY_DEPROVISION_SATELLITE_TOKENS);
3751                                 executor.execute(() -> Binder.withCleanCallingIdentity(() ->
3752                                         callback.onResult(null)));
3753                             } else {
3754                                 loge("KEY_DEPROVISION_SATELLITE_TOKENS does not exist.");
3755                                 executor.execute(() -> Binder.withCleanCallingIdentity(() ->
3756                                         callback.onError(new SatelliteException(
3757                                                 SATELLITE_RESULT_REQUEST_FAILED))));
3758                             }
3759                         } else {
3760                             executor.execute(() -> Binder.withCleanCallingIdentity(() ->
3761                                     callback.onError(new SatelliteException(resultCode))));
3762                         }
3763                     }
3764                 };
3765                 telephony.deprovisionSatellite(list, receiver);
3766             } else {
3767                 loge("deprovisionSatellite() invalid telephony");
3768                 executor.execute(() -> Binder.withCleanCallingIdentity(() -> callback.onError(
3769                         new SatelliteException(SATELLITE_RESULT_ILLEGAL_STATE))));
3770             }
3771         } catch (RemoteException ex) {
3772             loge("deprovisionSatellite() RemoteException: " + ex);
3773             executor.execute(() -> Binder.withCleanCallingIdentity(() -> callback.onError(
3774                     new SatelliteException(SATELLITE_RESULT_ILLEGAL_STATE))));
3775         }
3776     }
3777 
3778     /**
3779      * Inform whether application supports NTN SMS in satellite mode.
3780      *
3781      * This method is used by default messaging application to inform framework whether it supports
3782      * NTN SMS or not.
3783      *
3784      * Invoking this API will internally result in triggering
3785      * {@link android.telephony.TelephonyCallback.CarrierRoamingNtnModeListener
3786      * #onCarrierRoamingNtnAvailableServicesChanged(List)} and
3787      * {@link android.telephony.TelephonyCallback.CarrierRoamingNtnModeListener
3788      * #onCarrierRoamingNtnEligibleStateChanged(boolean)} callbacks.
3789      *
3790      * @param ntnSmsSupported {@code true} If application supports NTN SMS, else {@code false}.
3791      *
3792      * @throws SecurityException if the caller doesn't have required permission.
3793      * @throws IllegalStateException if the Telephony process is not currently available.
3794      * @hide
3795      */
3796     @RequiresPermission(allOf = {Manifest.permission.SATELLITE_COMMUNICATION,
3797             Manifest.permission.SEND_SMS})
setNtnSmsSupported(boolean ntnSmsSupported)3798     public void setNtnSmsSupported(boolean ntnSmsSupported) {
3799         try {
3800             ITelephony telephony = getITelephony();
3801             if (telephony != null) {
3802                 telephony.setNtnSmsSupported(ntnSmsSupported);
3803             } else {
3804                 throw new IllegalStateException("telephony service is null.");
3805             }
3806         } catch (RemoteException ex) {
3807             loge("setNtnSmsSupported() RemoteException:" + ex);
3808             ex.rethrowAsRuntimeException();
3809         }
3810     }
3811 
3812     /**
3813      * Get list of application packages name that are optimized for low bandwidth satellite data.
3814      *
3815      * @return List of application packages name with data optimized network property.
3816      *
3817      * {@link #PROPERTY_SATELLITE_DATA_OPTIMIZED}
3818      *
3819      * @hide
3820      */
3821     @SystemApi
3822     @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
3823     @FlaggedApi(Flags.FLAG_SATELLITE_25Q4_APIS)
getSatelliteDataOptimizedApps()3824     public @NonNull List<String> getSatelliteDataOptimizedApps() {
3825         List<String> appsNames = new ArrayList<>();
3826         try {
3827             ITelephony telephony = getITelephony();
3828             if (telephony != null) {
3829                 appsNames = telephony.getSatelliteDataOptimizedApps();
3830             } else {
3831                 throw new IllegalStateException("telephony service is null.");
3832             }
3833         } catch (RemoteException ex) {
3834             loge("getSatelliteDataOptimizedApps() RemoteException:" + ex);
3835             ex.rethrowAsRuntimeException();
3836         }
3837 
3838         return appsNames;
3839     }
3840 
3841     /**
3842      * Method to return the current satellite data service policy supported mode for the
3843      * subscriptionId based on carrier config.
3844      *
3845      * @param subId current subscription id.
3846      *
3847      * @return Supported modes {@link SatelliteDataSupportMode}
3848      * @throws IllegalArgumentException if the subscription is invalid.
3849      *
3850      * @hide
3851      */
3852     @SystemApi
3853     @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
3854     @FlaggedApi(Flags.FLAG_SATELLITE_25Q4_APIS)
3855     @SatelliteDataSupportMode
getSatelliteDataSupportMode(int subId)3856     public int getSatelliteDataSupportMode(int subId) {
3857         int satelliteMode = SATELLITE_DATA_SUPPORT_UNKNOWN;
3858 
3859         try {
3860             ITelephony telephony = getITelephony();
3861             if (telephony != null) {
3862                 satelliteMode = telephony.getSatelliteDataSupportMode(subId);
3863             } else {
3864                 throw new IllegalStateException("telephony service is null.");
3865             }
3866         } catch (RemoteException ex) {
3867             loge("getSatelliteDataSupportMode() RemoteException:" + ex);
3868             ex.rethrowAsRuntimeException();
3869         }
3870 
3871         return satelliteMode;
3872     }
3873 
3874     @Nullable
getITelephony()3875     private static ITelephony getITelephony() {
3876         ITelephony binder = ITelephony.Stub.asInterface(TelephonyFrameworkInitializer
3877                 .getTelephonyServiceManager()
3878                 .getTelephonyServiceRegisterer()
3879                 .get());
3880         return binder;
3881     }
3882 
logd(@onNull String log)3883     private static void logd(@NonNull String log) {
3884         Rlog.d(TAG, log);
3885     }
3886 
loge(@onNull String log)3887     private static void loge(@NonNull String log) {
3888         Rlog.e(TAG, log);
3889     }
3890 }
3891