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.IntDef;
23 import android.annotation.NonNull;
24 import android.annotation.Nullable;
25 import android.annotation.RequiresFeature;
26 import android.annotation.RequiresPermission;
27 import android.annotation.SystemApi;
28 import android.content.Context;
29 import android.content.pm.PackageManager;
30 import android.os.Binder;
31 import android.os.Bundle;
32 import android.os.CancellationSignal;
33 import android.os.ICancellationSignal;
34 import android.os.OutcomeReceiver;
35 import android.os.RemoteException;
36 import android.os.ResultReceiver;
37 import android.telephony.SubscriptionManager;
38 import android.telephony.TelephonyCallback;
39 import android.telephony.TelephonyFrameworkInitializer;
40 import android.telephony.TelephonyManager;
41 
42 import com.android.internal.telephony.IIntegerConsumer;
43 import com.android.internal.telephony.ITelephony;
44 import com.android.internal.telephony.IVoidConsumer;
45 import com.android.internal.telephony.flags.Flags;
46 import com.android.telephony.Rlog;
47 
48 import java.lang.annotation.Retention;
49 import java.lang.annotation.RetentionPolicy;
50 import java.time.Duration;
51 import java.util.ArrayList;
52 import java.util.Arrays;
53 import java.util.HashSet;
54 import java.util.List;
55 import java.util.Objects;
56 import java.util.Set;
57 import java.util.concurrent.ConcurrentHashMap;
58 import java.util.concurrent.Executor;
59 import java.util.function.Consumer;
60 import java.util.stream.Collectors;
61 
62 /**
63  * Manages satellite operations such as provisioning, pointing, messaging, location sharing, etc.
64  * To get the object, call {@link Context#getSystemService(String)}.
65  *
66  * @hide
67  */
68 @RequiresFeature(PackageManager.FEATURE_TELEPHONY_SATELLITE)
69 @SystemApi
70 @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
71 public final class SatelliteManager {
72     private static final String TAG = "SatelliteManager";
73 
74     private static final ConcurrentHashMap<SatelliteDatagramCallback, ISatelliteDatagramCallback>
75             sSatelliteDatagramCallbackMap = new ConcurrentHashMap<>();
76     private static final ConcurrentHashMap<SatelliteProvisionStateCallback,
77             ISatelliteProvisionStateCallback> sSatelliteProvisionStateCallbackMap =
78             new ConcurrentHashMap<>();
79     private static final ConcurrentHashMap<SatelliteModemStateCallback,
80             ISatelliteModemStateCallback>
81             sSatelliteModemStateCallbackMap = new ConcurrentHashMap<>();
82     private static final ConcurrentHashMap<SatelliteTransmissionUpdateCallback,
83             ISatelliteTransmissionUpdateCallback> sSatelliteTransmissionUpdateCallbackMap =
84             new ConcurrentHashMap<>();
85     private static final ConcurrentHashMap<NtnSignalStrengthCallback, INtnSignalStrengthCallback>
86             sNtnSignalStrengthCallbackMap = new ConcurrentHashMap<>();
87     private static final ConcurrentHashMap<SatelliteCapabilitiesCallback,
88             ISatelliteCapabilitiesCallback>
89             sSatelliteCapabilitiesCallbackMap = new ConcurrentHashMap<>();
90     private static final ConcurrentHashMap<SatelliteSupportedStateCallback,
91             ISatelliteSupportedStateCallback> sSatelliteSupportedStateCallbackMap =
92             new ConcurrentHashMap<>();
93 
94     private static final ConcurrentHashMap<SatelliteCommunicationAllowedStateCallback,
95             ISatelliteCommunicationAllowedStateCallback>
96             sSatelliteCommunicationAllowedStateCallbackMap =
97             new ConcurrentHashMap<>();
98 
99     private final int mSubId;
100 
101     /**
102      * Context this SatelliteManager is for.
103      */
104     @Nullable private final Context mContext;
105 
106     /**
107      * Create an instance of the SatelliteManager.
108      *
109      * @param context The context the SatelliteManager belongs to.
110      * @hide
111      */
SatelliteManager(@ullable Context context)112     public SatelliteManager(@Nullable Context context) {
113         this(context, SubscriptionManager.DEFAULT_SUBSCRIPTION_ID);
114     }
115 
116     /**
117      * Create an instance of the SatelliteManager associated with a particular subscription.
118      *
119      * @param context The context the SatelliteManager belongs to.
120      * @param subId The subscription ID associated with the SatelliteManager.
121      */
SatelliteManager(@ullable Context context, int subId)122     private SatelliteManager(@Nullable Context context, int subId) {
123         mContext = context;
124         mSubId = subId;
125     }
126 
127     /**
128      * Exception from the satellite service containing the {@link SatelliteResult} error code.
129      */
130     @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
131     public static class SatelliteException extends Exception {
132         @SatelliteResult private final int mErrorCode;
133 
134         /**
135          * Create a SatelliteException with a given error code.
136          *
137          * @param errorCode The {@link SatelliteResult}.
138          */
139         @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
SatelliteException(@atelliteResult int errorCode)140         public SatelliteException(@SatelliteResult int errorCode) {
141             mErrorCode = errorCode;
142         }
143 
144         /**
145          * Get the error code returned from the satellite service.
146          *
147          * @return The {@link SatelliteResult}.
148          */
149         @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
getErrorCode()150         @SatelliteResult public int getErrorCode() {
151             return mErrorCode;
152         }
153     }
154 
155     /**
156      * Bundle key to get the response from
157      * {@link #requestIsEnabled(Executor, OutcomeReceiver)}.
158      * @hide
159      */
160 
161     public static final String KEY_SATELLITE_ENABLED = "satellite_enabled";
162 
163     /**
164      * Bundle key to get the response from
165      * {@link #requestIsDemoModeEnabled(Executor, OutcomeReceiver)}.
166      * @hide
167      */
168 
169     public static final String KEY_DEMO_MODE_ENABLED = "demo_mode_enabled";
170 
171     /**
172      * Bundle key to get the response from
173      * {@link #requestIsEmergencyModeEnabled(Executor, OutcomeReceiver)}.
174      * @hide
175      */
176     public static final String KEY_EMERGENCY_MODE_ENABLED = "emergency_mode_enabled";
177 
178     /**
179      * Bundle key to get the response from
180      * {@link #requestIsSupported(Executor, OutcomeReceiver)}.
181      * @hide
182      */
183 
184     public static final String KEY_SATELLITE_SUPPORTED = "satellite_supported";
185 
186     /**
187      * Bundle key to get the response from
188      * {@link #requestCapabilities(Executor, OutcomeReceiver)}.
189      * @hide
190      */
191 
192     public static final String KEY_SATELLITE_CAPABILITIES = "satellite_capabilities";
193 
194     /**
195      * Bundle key to get the response from
196      * {@link #requestSessionStats(Executor, OutcomeReceiver)}.
197      * @hide
198      */
199 
200     public static final String KEY_SESSION_STATS = "session_stats";
201 
202     /**
203      * Bundle key to get the response from
204      * {@link #requestIsProvisioned(Executor, OutcomeReceiver)}.
205      * @hide
206      */
207 
208     public static final String KEY_SATELLITE_PROVISIONED = "satellite_provisioned";
209 
210     /**
211      * Bundle key to get the response from
212      * {@link #requestIsCommunicationAllowedForCurrentLocation(Executor, OutcomeReceiver)}.
213      * @hide
214      */
215 
216     public static final String KEY_SATELLITE_COMMUNICATION_ALLOWED =
217             "satellite_communication_allowed";
218 
219     /**
220      * Bundle key to get the response from
221      * {@link #requestTimeForNextSatelliteVisibility(Executor, OutcomeReceiver)}.
222      * @hide
223      */
224 
225     public static final String KEY_SATELLITE_NEXT_VISIBILITY = "satellite_next_visibility";
226 
227     /**
228      * Bundle key to get the response from
229      * {@link #requestNtnSignalStrength(Executor, OutcomeReceiver)}.
230      * @hide
231      */
232 
233     public static final String KEY_NTN_SIGNAL_STRENGTH = "ntn_signal_strength";
234 
235     /**
236      * The request was successfully processed.
237      */
238     @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
239     public static final int SATELLITE_RESULT_SUCCESS = 0;
240     /**
241      * A generic error which should be used only when other specific errors cannot be used.
242      */
243     @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
244     public static final int SATELLITE_RESULT_ERROR = 1;
245     /**
246      * Error received from the satellite server.
247      */
248     @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
249     public static final int SATELLITE_RESULT_SERVER_ERROR = 2;
250     /**
251      * Error received from the vendor service. This generic error code should be used
252      * only when the error cannot be mapped to other specific service error codes.
253      */
254     @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
255     public static final int SATELLITE_RESULT_SERVICE_ERROR = 3;
256     /**
257      * Error received from satellite modem. This generic error code should be used only when
258      * the error cannot be mapped to other specific modem error codes.
259      */
260     @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
261     public static final int SATELLITE_RESULT_MODEM_ERROR = 4;
262     /**
263      * Error received from the satellite network. This generic error code should be used only when
264      * the error cannot be mapped to other specific network error codes.
265      */
266     @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
267     public static final int SATELLITE_RESULT_NETWORK_ERROR = 5;
268     /**
269      * Telephony is not in a valid state to receive requests from clients.
270      */
271     @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
272     public static final int SATELLITE_RESULT_INVALID_TELEPHONY_STATE = 6;
273     /**
274      * Satellite modem is not in a valid state to receive requests from clients.
275      */
276     @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
277     public static final int SATELLITE_RESULT_INVALID_MODEM_STATE = 7;
278     /**
279      * Either vendor service, or modem, or Telephony framework has received a request with
280      * invalid arguments from its clients.
281      */
282     @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
283     public static final int SATELLITE_RESULT_INVALID_ARGUMENTS = 8;
284     /**
285      * Telephony framework failed to send a request or receive a response from the vendor service
286      * or satellite modem due to internal error.
287      */
288     @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
289     public static final int SATELLITE_RESULT_REQUEST_FAILED = 9;
290     /**
291      * Radio did not start or is resetting.
292      */
293     @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
294     public static final int SATELLITE_RESULT_RADIO_NOT_AVAILABLE = 10;
295     /**
296      * The request is not supported by either the satellite modem or the network.
297      */
298     @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
299     public static final int SATELLITE_RESULT_REQUEST_NOT_SUPPORTED = 11;
300     /**
301      * Satellite modem or network has no resources available to handle requests from clients.
302      */
303     @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
304     public static final int SATELLITE_RESULT_NO_RESOURCES = 12;
305     /**
306      * Satellite service is not provisioned yet.
307      */
308     @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
309     public static final int SATELLITE_RESULT_SERVICE_NOT_PROVISIONED = 13;
310     /**
311      * Satellite service provision is already in progress.
312      */
313     @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
314     public static final int SATELLITE_RESULT_SERVICE_PROVISION_IN_PROGRESS = 14;
315     /**
316      * The ongoing request was aborted by either the satellite modem or the network.
317      * This error is also returned when framework decides to abort current send request as one
318      * of the previous send request failed.
319      */
320     @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
321     public static final int SATELLITE_RESULT_REQUEST_ABORTED = 15;
322     /**
323      * The device/subscriber is barred from accessing the satellite service.
324      */
325     @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
326     public static final int SATELLITE_RESULT_ACCESS_BARRED = 16;
327     /**
328      * Satellite modem timeout to receive ACK or response from the satellite network after
329      * sending a request to the network.
330      */
331     @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
332     public static final int SATELLITE_RESULT_NETWORK_TIMEOUT = 17;
333     /**
334      * Satellite network is not reachable from the modem.
335      */
336     @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
337     public static final int SATELLITE_RESULT_NOT_REACHABLE = 18;
338     /**
339      * The device/subscriber is not authorized to register with the satellite service provider.
340      */
341     @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
342     public static final int SATELLITE_RESULT_NOT_AUTHORIZED = 19;
343     /**
344      * The device does not support satellite.
345      */
346     @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
347     public static final int SATELLITE_RESULT_NOT_SUPPORTED = 20;
348 
349     /**
350      * The current request is already in-progress.
351      */
352     @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
353     public static final int SATELLITE_RESULT_REQUEST_IN_PROGRESS = 21;
354 
355     /**
356      * Satellite modem is currently busy due to which current request cannot be processed.
357      */
358     @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
359     public static final int SATELLITE_RESULT_MODEM_BUSY = 22;
360 
361     /**
362      * Telephony process is not currently available or satellite is not supported.
363      */
364     @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
365     public static final int SATELLITE_RESULT_ILLEGAL_STATE = 23;
366 
367     /**
368      * Telephony framework timeout to receive ACK or response from the satellite modem after
369      * sending a request to the modem.
370      */
371     @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
372     public static final int SATELLITE_RESULT_MODEM_TIMEOUT = 24;
373 
374     /**
375      * Telephony framework needs to access the current location of the device to perform the
376      * request. However, location in the settings is disabled by users.
377      *
378      * @hide
379      */
380     @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
381     public static final int SATELLITE_RESULT_LOCATION_DISABLED = 25;
382 
383     /**
384      * Telephony framework needs to access the current location of the device to perform the
385      * request. However, Telephony fails to fetch the current location from location service.
386      *
387      * @hide
388      */
389     @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
390     public static final int SATELLITE_RESULT_LOCATION_NOT_AVAILABLE = 26;
391 
392     /** @hide */
393     @IntDef(prefix = {"SATELLITE_RESULT_"}, value = {
394             SATELLITE_RESULT_SUCCESS,
395             SATELLITE_RESULT_ERROR,
396             SATELLITE_RESULT_SERVER_ERROR,
397             SATELLITE_RESULT_SERVICE_ERROR,
398             SATELLITE_RESULT_MODEM_ERROR,
399             SATELLITE_RESULT_NETWORK_ERROR,
400             SATELLITE_RESULT_INVALID_TELEPHONY_STATE,
401             SATELLITE_RESULT_INVALID_MODEM_STATE,
402             SATELLITE_RESULT_INVALID_ARGUMENTS,
403             SATELLITE_RESULT_REQUEST_FAILED,
404             SATELLITE_RESULT_RADIO_NOT_AVAILABLE,
405             SATELLITE_RESULT_REQUEST_NOT_SUPPORTED,
406             SATELLITE_RESULT_NO_RESOURCES,
407             SATELLITE_RESULT_SERVICE_NOT_PROVISIONED,
408             SATELLITE_RESULT_SERVICE_PROVISION_IN_PROGRESS,
409             SATELLITE_RESULT_REQUEST_ABORTED,
410             SATELLITE_RESULT_ACCESS_BARRED,
411             SATELLITE_RESULT_NETWORK_TIMEOUT,
412             SATELLITE_RESULT_NOT_REACHABLE,
413             SATELLITE_RESULT_NOT_AUTHORIZED,
414             SATELLITE_RESULT_NOT_SUPPORTED,
415             SATELLITE_RESULT_REQUEST_IN_PROGRESS,
416             SATELLITE_RESULT_MODEM_BUSY,
417             SATELLITE_RESULT_ILLEGAL_STATE,
418             SATELLITE_RESULT_MODEM_TIMEOUT,
419             SATELLITE_RESULT_LOCATION_DISABLED,
420             SATELLITE_RESULT_LOCATION_NOT_AVAILABLE
421     })
422     @Retention(RetentionPolicy.SOURCE)
423     public @interface SatelliteResult {}
424 
425     /**
426      * Unknown Non-Terrestrial radio technology. This generic radio technology should be used
427      * only when the radio technology cannot be mapped to other specific radio technologies.
428      */
429     @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
430     public static final int NT_RADIO_TECHNOLOGY_UNKNOWN = 0;
431     /**
432      * 3GPP NB-IoT (Narrowband Internet of Things) over Non-Terrestrial-Networks technology.
433      */
434     @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
435     public static final int NT_RADIO_TECHNOLOGY_NB_IOT_NTN = 1;
436     /**
437      * 3GPP 5G NR over Non-Terrestrial-Networks technology.
438      */
439     @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
440     public static final int NT_RADIO_TECHNOLOGY_NR_NTN = 2;
441     /**
442      * 3GPP eMTC (enhanced Machine-Type Communication) over Non-Terrestrial-Networks technology.
443      */
444     @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
445     public static final int NT_RADIO_TECHNOLOGY_EMTC_NTN = 3;
446     /**
447      * Proprietary technology.
448      */
449     @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
450     public static final int NT_RADIO_TECHNOLOGY_PROPRIETARY = 4;
451 
452     /** @hide */
453     @IntDef(prefix = "NT_RADIO_TECHNOLOGY_", value = {
454             NT_RADIO_TECHNOLOGY_UNKNOWN,
455             NT_RADIO_TECHNOLOGY_NB_IOT_NTN,
456             NT_RADIO_TECHNOLOGY_NR_NTN,
457             NT_RADIO_TECHNOLOGY_EMTC_NTN,
458             NT_RADIO_TECHNOLOGY_PROPRIETARY
459     })
460     @Retention(RetentionPolicy.SOURCE)
461     public @interface NTRadioTechnology {}
462 
463     /** Suggested device hold position is unknown. */
464     @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
465     public static final int DEVICE_HOLD_POSITION_UNKNOWN = 0;
466     /** User is suggested to hold the device in portrait mode. */
467     @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
468     public static final int DEVICE_HOLD_POSITION_PORTRAIT = 1;
469     /** User is suggested to hold the device in landscape mode with left hand. */
470     @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
471     public static final int DEVICE_HOLD_POSITION_LANDSCAPE_LEFT = 2;
472     /** User is suggested to hold the device in landscape mode with right hand. */
473     @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
474     public static final int DEVICE_HOLD_POSITION_LANDSCAPE_RIGHT = 3;
475 
476     /** @hide */
477     @IntDef(prefix = {"DEVICE_HOLD_POSITION_"}, value = {
478             DEVICE_HOLD_POSITION_UNKNOWN,
479             DEVICE_HOLD_POSITION_PORTRAIT,
480             DEVICE_HOLD_POSITION_LANDSCAPE_LEFT,
481             DEVICE_HOLD_POSITION_LANDSCAPE_RIGHT
482        })
483     @Retention(RetentionPolicy.SOURCE)
484     public @interface DeviceHoldPosition {}
485 
486     /** Display mode is unknown. */
487     @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
488     public static final int DISPLAY_MODE_UNKNOWN = 0;
489     /** Display mode of the device used for satellite communication for non-foldable phones. */
490     @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
491     public static final int DISPLAY_MODE_FIXED = 1;
492     /** Display mode of the device used for satellite communication for foldabale phones when the
493      * device is opened. */
494     @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
495     public static final int DISPLAY_MODE_OPENED = 2;
496     /** Display mode of the device used for satellite communication for foldabable phones when the
497      * device is closed. */
498     @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
499     public static final int DISPLAY_MODE_CLOSED = 3;
500 
501     /** @hide */
502     @IntDef(prefix = {"ANTENNA_POSITION_"}, value = {
503             DISPLAY_MODE_UNKNOWN,
504             DISPLAY_MODE_FIXED,
505             DISPLAY_MODE_OPENED,
506             DISPLAY_MODE_CLOSED
507     })
508     @Retention(RetentionPolicy.SOURCE)
509     public @interface DisplayMode {}
510 
511     /**
512      * The emergency call is handed over to oem-enabled satellite SOS messaging. SOS messages are
513      * sent to SOS providers, which will then forward the messages to emergency providers.
514      */
515     @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
516     public static final int EMERGENCY_CALL_TO_SATELLITE_HANDOVER_TYPE_SOS = 1;
517     /**
518      * The emergency call is handed over to carrier-enabled satellite T911 messaging. T911 messages
519      * are sent directly to local emergency providers.
520      */
521     @FlaggedApi(Flags.FLAG_CARRIER_ENABLED_SATELLITE_FLAG)
522     public static final int EMERGENCY_CALL_TO_SATELLITE_HANDOVER_TYPE_T911 = 2;
523 
524     /**
525      * Request to enable or disable the satellite modem and demo mode.
526      * If satellite modem and cellular modem cannot work concurrently,
527      * then this will disable the cellular modem if satellite modem is enabled,
528      * and will re-enable the cellular modem if satellite modem is disabled.
529      *
530      * Demo mode is created to simulate the experience of sending and receiving messages over
531      * satellite. If user enters demo mode, a request should be sent to framework to enable
532      * satellite with enableDemoMode set to {code true}. Once satellite is enabled and device is
533      * aligned with the satellite, user can send a message and also receive a reply in demo mode.
534      * If enableSatellite is {@code false}, enableDemoMode has no impact on the behavior.
535      *
536      * @param attributes The attributes of the enable request.
537      * @param executor The executor on which the error code listener will be called.
538      * @param resultListener Listener for the {@link SatelliteResult} result of the operation.
539      *
540      * @throws SecurityException if the caller doesn't have required permission.
541      */
542     @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
543     @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
requestEnabled(@onNull EnableRequestAttributes attributes, @NonNull @CallbackExecutor Executor executor, @SatelliteResult @NonNull Consumer<Integer> resultListener)544     public void requestEnabled(@NonNull EnableRequestAttributes attributes,
545             @NonNull @CallbackExecutor Executor executor,
546             @SatelliteResult @NonNull Consumer<Integer> resultListener) {
547         Objects.requireNonNull(attributes);
548         Objects.requireNonNull(executor);
549         Objects.requireNonNull(resultListener);
550 
551         try {
552             ITelephony telephony = getITelephony();
553             if (telephony != null) {
554                 IIntegerConsumer errorCallback = new IIntegerConsumer.Stub() {
555                     @Override
556                     public void accept(int result) {
557                         executor.execute(() -> Binder.withCleanCallingIdentity(
558                                 () -> resultListener.accept(result)));
559                     }
560                 };
561                 telephony.requestSatelliteEnabled(mSubId, attributes.isEnabled(),
562                         attributes.isDemoMode(), attributes.isEmergencyMode(), errorCallback);
563             } else {
564                 Rlog.e(TAG, "requestEnabled() invalid telephony");
565                 executor.execute(() -> Binder.withCleanCallingIdentity(
566                         () -> resultListener.accept(SATELLITE_RESULT_ILLEGAL_STATE)));
567             }
568         } catch (RemoteException ex) {
569             Rlog.e(TAG, "requestEnabled() exception: ", ex);
570             executor.execute(() -> Binder.withCleanCallingIdentity(
571                     () -> resultListener.accept(SATELLITE_RESULT_ILLEGAL_STATE)));
572         }
573     }
574 
575     /**
576      * Request to get whether the satellite modem is enabled.
577      *
578      * @param executor The executor on which the callback will be called.
579      * @param callback The callback object to which the result will be delivered.
580      *                 If the request is successful, {@link OutcomeReceiver#onResult(Object)}
581      *                 will return a {@code boolean} with value {@code true} if the satellite modem
582      *                 is enabled and {@code false} otherwise.
583      *                 If the request is not successful, {@link OutcomeReceiver#onError(Throwable)}
584      *                 will return a {@link SatelliteException} with the {@link SatelliteResult}.
585      *
586      * @throws SecurityException if the caller doesn't have required permission.
587      */
588     @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
589     @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
requestIsEnabled(@onNull @allbackExecutor Executor executor, @NonNull OutcomeReceiver<Boolean, SatelliteException> callback)590     public void requestIsEnabled(@NonNull @CallbackExecutor Executor executor,
591             @NonNull OutcomeReceiver<Boolean, SatelliteException> callback) {
592         Objects.requireNonNull(executor);
593         Objects.requireNonNull(callback);
594 
595         try {
596             ITelephony telephony = getITelephony();
597             if (telephony != null) {
598                 ResultReceiver receiver = new ResultReceiver(null) {
599                     @Override
600                     protected void onReceiveResult(int resultCode, Bundle resultData) {
601                         if (resultCode == SATELLITE_RESULT_SUCCESS) {
602                             if (resultData.containsKey(KEY_SATELLITE_ENABLED)) {
603                                 boolean isSatelliteEnabled =
604                                         resultData.getBoolean(KEY_SATELLITE_ENABLED);
605                                 executor.execute(() -> Binder.withCleanCallingIdentity(() ->
606                                         callback.onResult(isSatelliteEnabled)));
607                             } else {
608                                 loge("KEY_SATELLITE_ENABLED does not exist.");
609                                 executor.execute(() -> Binder.withCleanCallingIdentity(() ->
610                                         callback.onError(new SatelliteException(
611                                                 SATELLITE_RESULT_REQUEST_FAILED))));
612                             }
613                         } else {
614                             executor.execute(() -> Binder.withCleanCallingIdentity(() ->
615                                     callback.onError(new SatelliteException(resultCode))));
616                         }
617                     }
618                 };
619                 telephony.requestIsSatelliteEnabled(mSubId, receiver);
620             } else {
621                 loge("requestIsEnabled() invalid telephony");
622                 executor.execute(() -> Binder.withCleanCallingIdentity(() -> callback.onError(
623                         new SatelliteException(SATELLITE_RESULT_ILLEGAL_STATE))));
624             }
625         } catch (RemoteException ex) {
626             loge("requestIsEnabled() RemoteException: " + ex);
627             executor.execute(() -> Binder.withCleanCallingIdentity(() -> callback.onError(
628                     new SatelliteException(SATELLITE_RESULT_ILLEGAL_STATE))));
629         }
630     }
631 
632     /**
633      * Request to get whether the satellite service demo mode is enabled.
634      *
635      * @param executor The executor on which the callback will be called.
636      * @param callback The callback object to which the result will be delivered.
637      *                 If the request is successful, {@link OutcomeReceiver#onResult(Object)}
638      *                 will return a {@code boolean} with value {@code true} if demo mode is enabled
639      *                 and {@code false} otherwise.
640      *                 If the request is not successful, {@link OutcomeReceiver#onError(Throwable)}
641      *                 will return a {@link SatelliteException} with the {@link SatelliteResult}.
642      *
643      * @throws SecurityException if the caller doesn't have required permission.
644      */
645     @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
646     @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
requestIsDemoModeEnabled(@onNull @allbackExecutor Executor executor, @NonNull OutcomeReceiver<Boolean, SatelliteException> callback)647     public void requestIsDemoModeEnabled(@NonNull @CallbackExecutor Executor executor,
648             @NonNull OutcomeReceiver<Boolean, SatelliteException> callback) {
649         Objects.requireNonNull(executor);
650         Objects.requireNonNull(callback);
651 
652         try {
653             ITelephony telephony = getITelephony();
654             if (telephony != null) {
655                 ResultReceiver receiver = new ResultReceiver(null) {
656                     @Override
657                     protected void onReceiveResult(int resultCode, Bundle resultData) {
658                         if (resultCode == SATELLITE_RESULT_SUCCESS) {
659                             if (resultData.containsKey(KEY_DEMO_MODE_ENABLED)) {
660                                 boolean isDemoModeEnabled =
661                                         resultData.getBoolean(KEY_DEMO_MODE_ENABLED);
662                                 executor.execute(() -> Binder.withCleanCallingIdentity(() ->
663                                         callback.onResult(isDemoModeEnabled)));
664                             } else {
665                                 loge("KEY_DEMO_MODE_ENABLED does not exist.");
666                                 executor.execute(() -> Binder.withCleanCallingIdentity(() ->
667                                         callback.onError(new SatelliteException(
668                                                 SATELLITE_RESULT_REQUEST_FAILED))));
669                             }
670                         } else {
671                             executor.execute(() -> Binder.withCleanCallingIdentity(() ->
672                                     callback.onError(new SatelliteException(resultCode))));
673                         }
674                     }
675                 };
676                 telephony.requestIsDemoModeEnabled(mSubId, receiver);
677             } else {
678                 loge("requestIsDemoModeEnabled() invalid telephony");
679                 executor.execute(() -> Binder.withCleanCallingIdentity(() -> callback.onError(
680                         new SatelliteException(SATELLITE_RESULT_ILLEGAL_STATE))));
681             }
682         } catch (RemoteException ex) {
683             loge("requestIsDemoModeEnabled() RemoteException: " + ex);
684             executor.execute(() -> Binder.withCleanCallingIdentity(() -> callback.onError(
685                     new SatelliteException(SATELLITE_RESULT_ILLEGAL_STATE))));
686         }
687     }
688 
689     /**
690      * Request to get whether the satellite service is enabled for emergency mode.
691      *
692      * @param executor The executor on which the callback will be called.
693      * @param callback The callback object to which the result will be delivered.
694      *                 If the request is successful, {@link OutcomeReceiver#onResult(Object)}
695      *                 will return a {@code boolean} with value {@code true} if satellite is enabled
696      *                 for emergency mode and {@code false} otherwise.
697      *                 If the request is not successful, {@link OutcomeReceiver#onError(Throwable)}
698      *                 will return a {@link SatelliteException} with the {@link SatelliteResult}.
699      *
700      * @throws SecurityException if the caller doesn't have required permission.
701      */
702     @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
703     @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
requestIsEmergencyModeEnabled(@onNull @allbackExecutor Executor executor, @NonNull OutcomeReceiver<Boolean, SatelliteException> callback)704     public void requestIsEmergencyModeEnabled(@NonNull @CallbackExecutor Executor executor,
705             @NonNull OutcomeReceiver<Boolean, SatelliteException> callback) {
706         Objects.requireNonNull(executor);
707         Objects.requireNonNull(callback);
708 
709         try {
710             ITelephony telephony = getITelephony();
711             if (telephony != null) {
712                 ResultReceiver receiver = new ResultReceiver(null) {
713                     @Override
714                     protected void onReceiveResult(int resultCode, Bundle resultData) {
715                         if (resultCode == SATELLITE_RESULT_SUCCESS) {
716                             if (resultData.containsKey(KEY_EMERGENCY_MODE_ENABLED)) {
717                                 boolean isEmergencyModeEnabled =
718                                         resultData.getBoolean(KEY_EMERGENCY_MODE_ENABLED);
719                                 executor.execute(() -> Binder.withCleanCallingIdentity(() ->
720                                         callback.onResult(isEmergencyModeEnabled)));
721                             } else {
722                                 loge("KEY_EMERGENCY_MODE_ENABLED does not exist.");
723                                 executor.execute(() -> Binder.withCleanCallingIdentity(() ->
724                                         callback.onError(new SatelliteException(
725                                                 SATELLITE_RESULT_REQUEST_FAILED))));
726                             }
727                         } else {
728                             executor.execute(() -> Binder.withCleanCallingIdentity(() ->
729                                     callback.onError(new SatelliteException(resultCode))));
730                         }
731                     }
732                 };
733                 telephony.requestIsEmergencyModeEnabled(mSubId, receiver);
734             } else {
735                 executor.execute(() -> Binder.withCleanCallingIdentity(() -> callback.onError(
736                         new SatelliteException(SATELLITE_RESULT_ILLEGAL_STATE))));
737             }
738         } catch (RemoteException ex) {
739             loge("requestIsEmergencyModeEnabled() RemoteException: " + ex);
740             ex.rethrowAsRuntimeException();
741         }
742     }
743 
744     /**
745      * Request to get whether the satellite service is supported on the device.
746      *
747      * <p>
748      * Note: This API only checks whether the device supports the satellite feature. The result will
749      * not be affected by whether the device is provisioned.
750      * </p>
751      *
752      * @param executor The executor on which the callback will be called.
753      * @param callback The callback object to which the result will be delivered.
754      *                 If the request is successful, {@link OutcomeReceiver#onResult(Object)}
755      *                 will return a {@code boolean} with value {@code true} if the satellite
756      *                 service is supported on the device and {@code false} otherwise.
757      *                 If the request is not successful, {@link OutcomeReceiver#onError(Throwable)}
758      *                 will return a {@link SatelliteException} with the {@link SatelliteResult}.
759      */
760     @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
requestIsSupported(@onNull @allbackExecutor Executor executor, @NonNull OutcomeReceiver<Boolean, SatelliteException> callback)761     public void requestIsSupported(@NonNull @CallbackExecutor Executor executor,
762             @NonNull OutcomeReceiver<Boolean, SatelliteException> callback) {
763         Objects.requireNonNull(executor);
764         Objects.requireNonNull(callback);
765 
766         try {
767             ITelephony telephony = getITelephony();
768             if (telephony != null) {
769                 ResultReceiver receiver = new ResultReceiver(null) {
770                     @Override
771                     protected void onReceiveResult(int resultCode, Bundle resultData) {
772                         if (resultCode == SATELLITE_RESULT_SUCCESS) {
773                             if (resultData.containsKey(KEY_SATELLITE_SUPPORTED)) {
774                                 boolean isSatelliteSupported =
775                                         resultData.getBoolean(KEY_SATELLITE_SUPPORTED);
776                                 executor.execute(() -> Binder.withCleanCallingIdentity(() ->
777                                         callback.onResult(isSatelliteSupported)));
778                             } else {
779                                 loge("KEY_SATELLITE_SUPPORTED does not exist.");
780                                 executor.execute(() -> Binder.withCleanCallingIdentity(() ->
781                                         callback.onError(new SatelliteException(
782                                                 SATELLITE_RESULT_REQUEST_FAILED))));
783                             }
784                         } else {
785                             executor.execute(() -> Binder.withCleanCallingIdentity(() ->
786                                     callback.onError(new SatelliteException(resultCode))));
787                         }
788                     }
789                 };
790                 telephony.requestIsSatelliteSupported(mSubId, receiver);
791             } else {
792                 loge("requestIsSupported() invalid telephony");
793                 executor.execute(() -> Binder.withCleanCallingIdentity(() -> callback.onError(
794                         new SatelliteException(SATELLITE_RESULT_ILLEGAL_STATE))));
795             }
796         } catch (RemoteException ex) {
797             loge("requestIsSupported() RemoteException: " + ex);
798             executor.execute(() -> Binder.withCleanCallingIdentity(() -> callback.onError(
799                     new SatelliteException(SATELLITE_RESULT_ILLEGAL_STATE))));
800         }
801     }
802 
803     /**
804      * Request to get the {@link SatelliteCapabilities} of the satellite service.
805      *
806      * @param executor The executor on which the callback will be called.
807      * @param callback The callback object to which the result will be delivered.
808      *                 If the request is successful, {@link OutcomeReceiver#onResult(Object)}
809      *                 will return the {@link SatelliteCapabilities} of the satellite service.
810      *                 If the request is not successful, {@link OutcomeReceiver#onError(Throwable)}
811      *                 will return a {@link SatelliteException} with the {@link SatelliteResult}.
812      *
813      * @throws SecurityException if the caller doesn't have required permission.
814      */
815     @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
816     @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
requestCapabilities(@onNull @allbackExecutor Executor executor, @NonNull OutcomeReceiver<SatelliteCapabilities, SatelliteException> callback)817     public void requestCapabilities(@NonNull @CallbackExecutor Executor executor,
818             @NonNull OutcomeReceiver<SatelliteCapabilities, SatelliteException> callback) {
819         Objects.requireNonNull(executor);
820         Objects.requireNonNull(callback);
821 
822         try {
823             ITelephony telephony = getITelephony();
824             if (telephony != null) {
825                 ResultReceiver receiver = new ResultReceiver(null) {
826                     @Override
827                     protected void onReceiveResult(int resultCode, Bundle resultData) {
828                         if (resultCode == SATELLITE_RESULT_SUCCESS) {
829                             if (resultData.containsKey(KEY_SATELLITE_CAPABILITIES)) {
830                                 SatelliteCapabilities capabilities =
831                                         resultData.getParcelable(KEY_SATELLITE_CAPABILITIES,
832                                                 SatelliteCapabilities.class);
833                                 executor.execute(() -> Binder.withCleanCallingIdentity(() ->
834                                         callback.onResult(capabilities)));
835                             } else {
836                                 loge("KEY_SATELLITE_CAPABILITIES does not exist.");
837                                 executor.execute(() -> Binder.withCleanCallingIdentity(() ->
838                                         callback.onError(new SatelliteException(
839                                                 SATELLITE_RESULT_REQUEST_FAILED))));
840                             }
841                         } else {
842                             executor.execute(() -> Binder.withCleanCallingIdentity(() ->
843                                     callback.onError(new SatelliteException(resultCode))));
844                         }
845                     }
846                 };
847                 telephony.requestSatelliteCapabilities(mSubId, receiver);
848             } else {
849                 loge("requestCapabilities() invalid telephony");
850                 executor.execute(() -> Binder.withCleanCallingIdentity(() -> callback.onError(
851                         new SatelliteException(SATELLITE_RESULT_ILLEGAL_STATE))));
852             }
853         } catch (RemoteException ex) {
854             loge("requestCapabilities() RemoteException: " + ex);
855             executor.execute(() -> Binder.withCleanCallingIdentity(() -> callback.onError(
856                     new SatelliteException(SATELLITE_RESULT_ILLEGAL_STATE))));
857         }
858     }
859 
860     /**
861      * The default state indicating that datagram transfer is idle.
862      * This should be sent if there are no message transfer activity happening.
863      */
864     @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
865     public static final int SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE = 0;
866     /**
867      * A transition state indicating that a datagram is being sent.
868      */
869     @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
870     public static final int SATELLITE_DATAGRAM_TRANSFER_STATE_SENDING = 1;
871     /**
872      * An end state indicating that datagram sending completed successfully.
873      * After datagram transfer completes, {@link #SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE}
874      * will be sent if no more messages are pending.
875      */
876     @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
877     public static final int SATELLITE_DATAGRAM_TRANSFER_STATE_SEND_SUCCESS = 2;
878     /**
879      * An end state indicating that datagram sending completed with a failure.
880      * After datagram transfer completes, {@link #SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE}
881      * must be sent before reporting any additional datagram transfer state changes. All pending
882      * messages will be reported as failed, to the corresponding applications.
883      */
884     @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
885     public static final int SATELLITE_DATAGRAM_TRANSFER_STATE_SEND_FAILED = 3;
886     /**
887      * A transition state indicating that a datagram is being received.
888      */
889     @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
890     public static final int SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVING = 4;
891     /**
892      * An end state indicating that datagram receiving completed successfully.
893      * After datagram transfer completes, {@link #SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE}
894      * will be sent if no more messages are pending.
895      */
896     @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
897     public static final int SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVE_SUCCESS = 5;
898     /**
899      * An end state indicating that datagram receive operation found that there are no
900      * messages to be retrieved from the satellite.
901      * After datagram transfer completes, {@link #SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE}
902      * will be sent if no more messages are pending.
903      */
904     @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
905     public static final int SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVE_NONE = 6;
906     /**
907      * An end state indicating that datagram receive completed with a failure.
908      * After datagram transfer completes, {@link #SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE}
909      * will be sent if no more messages are pending.
910      */
911     @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
912     public static final int SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVE_FAILED = 7;
913     /**
914      * A transition state indicating that Telephony is waiting for satellite modem to connect to a
915      * satellite network before sending a datagram or polling for datagrams. If the satellite modem
916      * successfully connects to a satellite network, either
917      * {@link #SATELLITE_DATAGRAM_TRANSFER_STATE_SENDING} or
918      * {@link #SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVING} will be sent. Otherwise,
919      * either {@link #SATELLITE_DATAGRAM_TRANSFER_STATE_SEND_FAILED} or
920      * {@link #SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVE_FAILED} will be sent.
921      */
922     @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
923     public static final int SATELLITE_DATAGRAM_TRANSFER_STATE_WAITING_TO_CONNECT = 8;
924     /**
925      * The datagram transfer state is unknown. This generic datagram transfer state should be used
926      * only when the datagram transfer state cannot be mapped to other specific datagram transfer
927      * states.
928      */
929     @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
930     public static final int SATELLITE_DATAGRAM_TRANSFER_STATE_UNKNOWN = -1;
931 
932     /** @hide */
933     @IntDef(prefix = {"SATELLITE_DATAGRAM_TRANSFER_STATE_"}, value = {
934             SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE,
935             SATELLITE_DATAGRAM_TRANSFER_STATE_SENDING,
936             SATELLITE_DATAGRAM_TRANSFER_STATE_SEND_SUCCESS,
937             SATELLITE_DATAGRAM_TRANSFER_STATE_SEND_FAILED,
938             SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVING,
939             SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVE_SUCCESS,
940             SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVE_NONE,
941             SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVE_FAILED,
942             SATELLITE_DATAGRAM_TRANSFER_STATE_WAITING_TO_CONNECT,
943             SATELLITE_DATAGRAM_TRANSFER_STATE_UNKNOWN
944     })
945     @Retention(RetentionPolicy.SOURCE)
946     public @interface SatelliteDatagramTransferState {}
947     // TODO: Split into two enums for sending and receiving states
948 
949     /**
950      * Satellite modem is in idle state.
951      */
952     @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
953     public static final int SATELLITE_MODEM_STATE_IDLE = 0;
954     /**
955      * Satellite modem is listening for incoming datagrams.
956      */
957     @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
958     public static final int SATELLITE_MODEM_STATE_LISTENING = 1;
959     /**
960      * Satellite modem is sending and/or receiving datagrams.
961      */
962     @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
963     public static final int SATELLITE_MODEM_STATE_DATAGRAM_TRANSFERRING = 2;
964     /**
965      * Satellite modem is retrying to send and/or receive datagrams.
966      */
967     @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
968     public static final int SATELLITE_MODEM_STATE_DATAGRAM_RETRYING = 3;
969     /**
970      * Satellite modem is powered off.
971      */
972     @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
973     public static final int SATELLITE_MODEM_STATE_OFF = 4;
974     /**
975      * Satellite modem is unavailable.
976      */
977     @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
978     public static final int SATELLITE_MODEM_STATE_UNAVAILABLE = 5;
979     /**
980      * The satellite modem is powered on but the device is not registered to a satellite cell.
981      */
982     @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
983     public static final int SATELLITE_MODEM_STATE_NOT_CONNECTED = 6;
984     /**
985      * The satellite modem is powered on and the device is registered to a satellite cell.
986      */
987     @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
988     public static final int SATELLITE_MODEM_STATE_CONNECTED = 7;
989     /**
990      * The satellite modem is being powered on.
991      * @hide
992      */
993     public static final int SATELLITE_MODEM_STATE_ENABLING_SATELLITE = 8;
994     /**
995      * The satellite modem is being powered off.
996      * @hide
997      */
998     public static final int SATELLITE_MODEM_STATE_DISABLING_SATELLITE = 9;
999     /**
1000      * Satellite modem state is unknown. This generic modem state should be used only when the
1001      * modem state cannot be mapped to other specific modem states.
1002      */
1003     @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
1004     public static final int SATELLITE_MODEM_STATE_UNKNOWN = -1;
1005 
1006     /** @hide */
1007     @IntDef(prefix = {"SATELLITE_MODEM_STATE_"}, value = {
1008             SATELLITE_MODEM_STATE_IDLE,
1009             SATELLITE_MODEM_STATE_LISTENING,
1010             SATELLITE_MODEM_STATE_DATAGRAM_TRANSFERRING,
1011             SATELLITE_MODEM_STATE_DATAGRAM_RETRYING,
1012             SATELLITE_MODEM_STATE_OFF,
1013             SATELLITE_MODEM_STATE_UNAVAILABLE,
1014             SATELLITE_MODEM_STATE_NOT_CONNECTED,
1015             SATELLITE_MODEM_STATE_CONNECTED,
1016             SATELLITE_MODEM_STATE_ENABLING_SATELLITE,
1017             SATELLITE_MODEM_STATE_DISABLING_SATELLITE,
1018             SATELLITE_MODEM_STATE_UNKNOWN
1019     })
1020     @Retention(RetentionPolicy.SOURCE)
1021     public @interface SatelliteModemState {}
1022 
1023     /**
1024      * Datagram type is unknown. This generic datagram type should be used only when the
1025      * datagram type cannot be mapped to other specific datagram types.
1026      */
1027     @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
1028     public static final int DATAGRAM_TYPE_UNKNOWN = 0;
1029     /**
1030      * Datagram type indicating that the datagram to be sent or received is of type SOS message.
1031      */
1032     @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
1033     public static final int DATAGRAM_TYPE_SOS_MESSAGE = 1;
1034     /**
1035      * Datagram type indicating that the datagram to be sent or received is of type
1036      * location sharing.
1037      */
1038     @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
1039     public static final int DATAGRAM_TYPE_LOCATION_SHARING = 2;
1040     /**
1041      * This type of datagram is used to keep the device in satellite connected state or check if
1042      * there is any incoming message.
1043      * @hide
1044      */
1045     public static final int DATAGRAM_TYPE_KEEP_ALIVE = 3;
1046     /**
1047      * Datagram type indicating that the datagram to be sent or received is of type SOS message and
1048      * is the last message to emergency service provider indicating still needs help.
1049      * @hide
1050      */
1051     public static final int DATAGRAM_TYPE_LAST_SOS_MESSAGE_STILL_NEED_HELP = 4;
1052     /**
1053      * Datagram type indicating that the datagram to be sent or received is of type SOS message and
1054      * is the last message to emergency service provider indicating no more help is needed.
1055      * @hide
1056      */
1057     public static final int DATAGRAM_TYPE_LAST_SOS_MESSAGE_NO_HELP_NEEDED = 5;
1058 
1059     /** @hide */
1060     @IntDef(prefix = "DATAGRAM_TYPE_", value = {
1061             DATAGRAM_TYPE_UNKNOWN,
1062             DATAGRAM_TYPE_SOS_MESSAGE,
1063             DATAGRAM_TYPE_LOCATION_SHARING,
1064             DATAGRAM_TYPE_KEEP_ALIVE,
1065             DATAGRAM_TYPE_LAST_SOS_MESSAGE_STILL_NEED_HELP,
1066             DATAGRAM_TYPE_LAST_SOS_MESSAGE_NO_HELP_NEEDED
1067     })
1068     @Retention(RetentionPolicy.SOURCE)
1069     public @interface DatagramType {}
1070 
1071     /**
1072      * Satellite communication restricted by user.
1073      * @hide
1074      */
1075     public static final int SATELLITE_COMMUNICATION_RESTRICTION_REASON_USER = 0;
1076 
1077     /**
1078      * Satellite communication restricted by geolocation. This can be
1079      * triggered based upon geofence input provided by carrier to enable or disable satellite.
1080      */
1081     @FlaggedApi(Flags.FLAG_CARRIER_ENABLED_SATELLITE_FLAG)
1082     public static final int SATELLITE_COMMUNICATION_RESTRICTION_REASON_GEOLOCATION = 1;
1083 
1084     /**
1085      * Satellite communication restricted by entitlement server. This can be triggered based on
1086      * the EntitlementStatus value received from the entitlement server to enable or disable
1087      * satellite.
1088      */
1089     @FlaggedApi(Flags.FLAG_CARRIER_ENABLED_SATELLITE_FLAG)
1090     public static final int SATELLITE_COMMUNICATION_RESTRICTION_REASON_ENTITLEMENT = 2;
1091 
1092     /** @hide */
1093     @IntDef(prefix = "SATELLITE_COMMUNICATION_RESTRICTION_REASON_", value = {
1094             SATELLITE_COMMUNICATION_RESTRICTION_REASON_USER,
1095             SATELLITE_COMMUNICATION_RESTRICTION_REASON_GEOLOCATION,
1096             SATELLITE_COMMUNICATION_RESTRICTION_REASON_ENTITLEMENT
1097     })
1098     @Retention(RetentionPolicy.SOURCE)
1099     public @interface SatelliteCommunicationRestrictionReason {}
1100 
1101     /**
1102      * Start receiving satellite transmission updates.
1103      * This can be called by the pointing UI when the user starts pointing to the satellite.
1104      * Modem should continue to report the pointing input as the device or satellite moves.
1105      * Satellite transmission updates are started only on {@link #SATELLITE_RESULT_SUCCESS}.
1106      * All other results indicate that this operation failed.
1107      * Once satellite transmission updates begin, position and datagram transfer state updates
1108      * will be sent through {@link SatelliteTransmissionUpdateCallback}.
1109      *
1110      * @param executor The executor on which the callback and error code listener will be called.
1111      * @param resultListener Listener for the {@link SatelliteResult} result of the operation.
1112      * @param callback The callback to notify of satellite transmission updates.
1113      *
1114      * @throws SecurityException if the caller doesn't have required permission.
1115      */
1116     @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
1117     @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
1118     @SuppressWarnings("SamShouldBeLast")
startTransmissionUpdates(@onNull @allbackExecutor Executor executor, @SatelliteResult @NonNull Consumer<Integer> resultListener, @NonNull SatelliteTransmissionUpdateCallback callback)1119     public void startTransmissionUpdates(@NonNull @CallbackExecutor Executor executor,
1120             @SatelliteResult @NonNull Consumer<Integer> resultListener,
1121             @NonNull SatelliteTransmissionUpdateCallback callback) {
1122         Objects.requireNonNull(executor);
1123         Objects.requireNonNull(resultListener);
1124         Objects.requireNonNull(callback);
1125 
1126         try {
1127             ITelephony telephony = getITelephony();
1128             if (telephony != null) {
1129                 IIntegerConsumer errorCallback = new IIntegerConsumer.Stub() {
1130                     @Override
1131                     public void accept(int result) {
1132                         executor.execute(() -> Binder.withCleanCallingIdentity(
1133                                 () -> resultListener.accept(result)));
1134                     }
1135                 };
1136                 ISatelliteTransmissionUpdateCallback internalCallback =
1137                         new ISatelliteTransmissionUpdateCallback.Stub() {
1138 
1139                             @Override
1140                             public void onSatellitePositionChanged(PointingInfo pointingInfo) {
1141                                 executor.execute(() -> Binder.withCleanCallingIdentity(
1142                                         () -> callback.onSatellitePositionChanged(pointingInfo)));
1143                             }
1144 
1145                             @Override
1146                             public void onSendDatagramStateChanged(int datagramType, int state,
1147                                     int sendPendingCount, int errorCode) {
1148                                 executor.execute(() -> Binder.withCleanCallingIdentity(
1149                                         () -> callback.onSendDatagramStateChanged(datagramType,
1150                                                 state, sendPendingCount, errorCode)));
1151 
1152                                 // For backward compatibility
1153                                 executor.execute(() -> Binder.withCleanCallingIdentity(
1154                                         () -> callback.onSendDatagramStateChanged(
1155                                                 state, sendPendingCount, errorCode)));
1156                             }
1157 
1158                             @Override
1159                             public void onReceiveDatagramStateChanged(int state,
1160                                     int receivePendingCount, int errorCode) {
1161                                 executor.execute(() -> Binder.withCleanCallingIdentity(
1162                                         () -> callback.onReceiveDatagramStateChanged(
1163                                                 state, receivePendingCount, errorCode)));
1164                             }
1165                         };
1166                 sSatelliteTransmissionUpdateCallbackMap.put(callback, internalCallback);
1167                 telephony.startSatelliteTransmissionUpdates(mSubId, errorCallback,
1168                         internalCallback);
1169             } else {
1170                 loge("startTransmissionUpdates() invalid telephony");
1171                 executor.execute(() -> Binder.withCleanCallingIdentity(
1172                         () -> resultListener.accept(SATELLITE_RESULT_ILLEGAL_STATE)));
1173             }
1174         } catch (RemoteException ex) {
1175             loge("startTransmissionUpdates() RemoteException: " + ex);
1176             executor.execute(() -> Binder.withCleanCallingIdentity(
1177                     () -> resultListener.accept(SATELLITE_RESULT_ILLEGAL_STATE)));
1178         }
1179     }
1180 
1181     /**
1182      * Stop receiving satellite transmission updates.
1183      * This can be called by the pointing UI when the user stops pointing to the satellite.
1184      * Satellite transmission updates are stopped and the callback is unregistered only on
1185      * {@link #SATELLITE_RESULT_SUCCESS}. All other results that this operation failed.
1186      *
1187      * @param callback The callback that was passed to {@link
1188      * #startTransmissionUpdates(Executor, Consumer, SatelliteTransmissionUpdateCallback)}.
1189      * @param executor The executor on which the error code listener will be called.
1190      * @param resultListener Listener for the {@link SatelliteResult} result of the operation.
1191      *
1192      * @throws SecurityException if the caller doesn't have required permission.
1193      */
1194     @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
1195     @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
stopTransmissionUpdates(@onNull SatelliteTransmissionUpdateCallback callback, @SuppressWarnings("ListenerLast") @NonNull @CallbackExecutor Executor executor, @SuppressWarnings("ListenerLast") @SatelliteResult @NonNull Consumer<Integer> resultListener)1196     public void stopTransmissionUpdates(@NonNull SatelliteTransmissionUpdateCallback callback,
1197             @SuppressWarnings("ListenerLast") @NonNull @CallbackExecutor Executor executor,
1198             @SuppressWarnings("ListenerLast") @SatelliteResult @NonNull
1199             Consumer<Integer> resultListener) {
1200         Objects.requireNonNull(callback);
1201         Objects.requireNonNull(executor);
1202         Objects.requireNonNull(resultListener);
1203 
1204         ISatelliteTransmissionUpdateCallback internalCallback =
1205                 sSatelliteTransmissionUpdateCallbackMap.remove(callback);
1206 
1207         try {
1208             ITelephony telephony = getITelephony();
1209             if (telephony != null) {
1210                 if (internalCallback != null) {
1211                     IIntegerConsumer errorCallback = new IIntegerConsumer.Stub() {
1212                         @Override
1213                         public void accept(int result) {
1214                             executor.execute(() -> Binder.withCleanCallingIdentity(
1215                                     () -> resultListener.accept(result)));
1216                         }
1217                     };
1218                     telephony.stopSatelliteTransmissionUpdates(mSubId, errorCallback,
1219                             internalCallback);
1220                     // TODO: Notify SmsHandler that pointing UI stopped
1221                 } else {
1222                     loge("stopSatelliteTransmissionUpdates: No internal callback.");
1223                     executor.execute(() -> Binder.withCleanCallingIdentity(
1224                             () -> resultListener.accept(SATELLITE_RESULT_INVALID_ARGUMENTS)));
1225                 }
1226             } else {
1227                 loge("stopTransmissionUpdates() invalid telephony");
1228                 executor.execute(() -> Binder.withCleanCallingIdentity(
1229                         () -> resultListener.accept(SATELLITE_RESULT_ILLEGAL_STATE)));
1230             }
1231         } catch (RemoteException ex) {
1232             loge("stopTransmissionUpdates() RemoteException: " + ex);
1233             executor.execute(() -> Binder.withCleanCallingIdentity(
1234                     () -> resultListener.accept(SATELLITE_RESULT_ILLEGAL_STATE)));
1235         }
1236     }
1237 
1238     /**
1239      * Provision the device with a satellite provider.
1240      * This is needed if the provider allows dynamic registration.
1241      *
1242      * @param token The token is generated by the user which is used as a unique identifier for
1243      *              provisioning with satellite gateway.
1244      * @param provisionData Data from the provisioning app that can be used by provisioning server
1245      * @param cancellationSignal The optional signal used by the caller to cancel the provision
1246      *                           request. Even when the cancellation is signaled, Telephony will
1247      *                           still trigger the callback to return the result of this request.
1248      * @param executor The executor on which the error code listener will be called.
1249      * @param resultListener Listener for the {@link SatelliteResult} result of the operation.
1250      *
1251      * @throws SecurityException if the caller doesn't have required permission.
1252      */
1253     @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
1254     @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
provisionService(@onNull String token, @NonNull byte[] provisionData, @Nullable CancellationSignal cancellationSignal, @NonNull @CallbackExecutor Executor executor, @SatelliteResult @NonNull Consumer<Integer> resultListener)1255     public void provisionService(@NonNull String token, @NonNull byte[] provisionData,
1256             @Nullable CancellationSignal cancellationSignal,
1257             @NonNull @CallbackExecutor Executor executor,
1258             @SatelliteResult @NonNull Consumer<Integer> resultListener) {
1259         Objects.requireNonNull(token);
1260         Objects.requireNonNull(executor);
1261         Objects.requireNonNull(resultListener);
1262         Objects.requireNonNull(provisionData);
1263 
1264         ICancellationSignal cancelRemote = null;
1265         try {
1266             ITelephony telephony = getITelephony();
1267             if (telephony != null) {
1268                 IIntegerConsumer errorCallback = new IIntegerConsumer.Stub() {
1269                     @Override
1270                     public void accept(int result) {
1271                         executor.execute(() -> Binder.withCleanCallingIdentity(
1272                                 () -> resultListener.accept(result)));
1273                     }
1274                 };
1275                 cancelRemote = telephony.provisionSatelliteService(mSubId, token, provisionData,
1276                         errorCallback);
1277             } else {
1278                 loge("provisionService() invalid telephony");
1279                 executor.execute(() -> Binder.withCleanCallingIdentity(
1280                         () -> resultListener.accept(SATELLITE_RESULT_ILLEGAL_STATE)));
1281             }
1282         } catch (RemoteException ex) {
1283             loge("provisionService() RemoteException=" + ex);
1284             executor.execute(() -> Binder.withCleanCallingIdentity(
1285                     () -> resultListener.accept(SATELLITE_RESULT_ILLEGAL_STATE)));
1286         }
1287         if (cancellationSignal != null) {
1288             cancellationSignal.setRemote(cancelRemote);
1289         }
1290     }
1291 
1292     /**
1293      * Deprovision the device with the satellite provider.
1294      * This is needed if the provider allows dynamic registration. Once deprovisioned,
1295      * {@link SatelliteProvisionStateCallback#onSatelliteProvisionStateChanged(boolean)}
1296      * should report as deprovisioned.
1297      * For provisioning satellite service, refer to
1298      * {@link #provisionService(String, byte[], CancellationSignal, Executor, Consumer)}
1299      *
1300      * @param token The token of the device/subscription to be deprovisioned.
1301      *              This should match with the token passed as input in
1302      *              {@link #provisionService(String, byte[], CancellationSignal, Executor,
1303      *              Consumer)}
1304      * @param resultListener Listener for the {@link SatelliteResult} result of the operation.
1305      *
1306      * @throws SecurityException if the caller doesn't have required permission.
1307      */
1308     @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
1309     @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
deprovisionService(@onNull String token, @NonNull @CallbackExecutor Executor executor, @SatelliteResult @NonNull Consumer<Integer> resultListener)1310     public void deprovisionService(@NonNull String token,
1311             @NonNull @CallbackExecutor Executor executor,
1312             @SatelliteResult @NonNull Consumer<Integer> resultListener) {
1313         Objects.requireNonNull(token);
1314         Objects.requireNonNull(executor);
1315         Objects.requireNonNull(resultListener);
1316 
1317         try {
1318             ITelephony telephony = getITelephony();
1319             if (telephony != null) {
1320                 IIntegerConsumer errorCallback = new IIntegerConsumer.Stub() {
1321                     @Override
1322                     public void accept(int result) {
1323                         executor.execute(() -> Binder.withCleanCallingIdentity(
1324                                 () -> resultListener.accept(result)));
1325                     }
1326                 };
1327                 telephony.deprovisionSatelliteService(mSubId, token, errorCallback);
1328             } else {
1329                 loge("deprovisionService() invalid telephony");
1330                 executor.execute(() -> Binder.withCleanCallingIdentity(
1331                         () -> resultListener.accept(SATELLITE_RESULT_ILLEGAL_STATE)));
1332             }
1333         } catch (RemoteException ex) {
1334             loge("deprovisionService() RemoteException ex=" + ex);
1335             executor.execute(() -> Binder.withCleanCallingIdentity(
1336                     () -> resultListener.accept(SATELLITE_RESULT_ILLEGAL_STATE)));
1337         }
1338     }
1339 
1340     /**
1341      * Registers for the satellite provision state changed.
1342      *
1343      * @param executor The executor on which the callback will be called.
1344      * @param callback The callback to handle the satellite provision state changed event.
1345      *
1346      * @return The {@link SatelliteResult} result of the operation.
1347      *
1348      * @throws SecurityException if the caller doesn't have required permission.
1349      * @throws IllegalStateException if the Telephony process is not currently available.
1350      */
1351     @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
1352     @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
registerForProvisionStateChanged( @onNull @allbackExecutor Executor executor, @NonNull SatelliteProvisionStateCallback callback)1353     @SatelliteResult public int registerForProvisionStateChanged(
1354             @NonNull @CallbackExecutor Executor executor,
1355             @NonNull SatelliteProvisionStateCallback callback) {
1356         Objects.requireNonNull(executor);
1357         Objects.requireNonNull(callback);
1358 
1359         try {
1360             ITelephony telephony = getITelephony();
1361             if (telephony != null) {
1362                 ISatelliteProvisionStateCallback internalCallback =
1363                         new ISatelliteProvisionStateCallback.Stub() {
1364                             @Override
1365                             public void onSatelliteProvisionStateChanged(boolean provisioned) {
1366                                 executor.execute(() -> Binder.withCleanCallingIdentity(
1367                                         () -> callback.onSatelliteProvisionStateChanged(
1368                                                 provisioned)));
1369                             }
1370                         };
1371                 sSatelliteProvisionStateCallbackMap.put(callback, internalCallback);
1372                 return telephony.registerForSatelliteProvisionStateChanged(
1373                         mSubId, internalCallback);
1374             } else {
1375                 throw new IllegalStateException("telephony service is null.");
1376             }
1377         } catch (RemoteException ex) {
1378             loge("registerForProvisionStateChanged() RemoteException: " + ex);
1379             ex.rethrowAsRuntimeException();
1380         }
1381         return SATELLITE_RESULT_REQUEST_FAILED;
1382     }
1383 
1384     /**
1385      * Unregisters for the satellite provision state changed.
1386      * If callback was not registered before, the request will be ignored.
1387      *
1388      * @param callback The callback that was passed to
1389      * {@link #registerForProvisionStateChanged(Executor, SatelliteProvisionStateCallback)}
1390      *
1391      * @throws SecurityException if the caller doesn't have required permission.
1392      * @throws IllegalStateException if the Telephony process is not currently available.
1393      */
1394     @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
1395     @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
unregisterForProvisionStateChanged( @onNull SatelliteProvisionStateCallback callback)1396     public void unregisterForProvisionStateChanged(
1397             @NonNull SatelliteProvisionStateCallback callback) {
1398         Objects.requireNonNull(callback);
1399         ISatelliteProvisionStateCallback internalCallback =
1400                 sSatelliteProvisionStateCallbackMap.remove(callback);
1401 
1402         try {
1403             ITelephony telephony = getITelephony();
1404             if (telephony != null) {
1405                 if (internalCallback != null) {
1406                     telephony.unregisterForSatelliteProvisionStateChanged(mSubId, internalCallback);
1407                 } else {
1408                     loge("unregisterForProvisionStateChanged: No internal callback.");
1409                 }
1410             } else {
1411                 throw new IllegalStateException("telephony service is null.");
1412             }
1413         } catch (RemoteException ex) {
1414             loge("unregisterForProvisionStateChanged() RemoteException: " + ex);
1415             ex.rethrowAsRuntimeException();
1416         }
1417     }
1418 
1419     /**
1420      * Request to get whether this device is provisioned with a satellite provider.
1421      *
1422      * @param executor The executor on which the callback will be called.
1423      * @param callback The callback object to which the result will be delivered.
1424      *                 If the request is successful, {@link OutcomeReceiver#onResult(Object)}
1425      *                 will return a {@code boolean} with value {@code true} if the device is
1426      *                 provisioned with a satellite provider and {@code false} otherwise.
1427      *                 If the request is not successful, {@link OutcomeReceiver#onError(Throwable)}
1428      *                 will return a {@link SatelliteException} with the {@link SatelliteResult}.
1429      *
1430      * @throws SecurityException if the caller doesn't have required permission.
1431      */
1432     @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
1433     @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
requestIsProvisioned(@onNull @allbackExecutor Executor executor, @NonNull OutcomeReceiver<Boolean, SatelliteException> callback)1434     public void requestIsProvisioned(@NonNull @CallbackExecutor Executor executor,
1435             @NonNull OutcomeReceiver<Boolean, SatelliteException> callback) {
1436         Objects.requireNonNull(executor);
1437         Objects.requireNonNull(callback);
1438 
1439         try {
1440             ITelephony telephony = getITelephony();
1441             if (telephony != null) {
1442                 ResultReceiver receiver = new ResultReceiver(null) {
1443                     @Override
1444                     protected void onReceiveResult(int resultCode, Bundle resultData) {
1445                         if (resultCode == SATELLITE_RESULT_SUCCESS) {
1446                             if (resultData.containsKey(KEY_SATELLITE_PROVISIONED)) {
1447                                 boolean isSatelliteProvisioned =
1448                                         resultData.getBoolean(KEY_SATELLITE_PROVISIONED);
1449                                 executor.execute(() -> Binder.withCleanCallingIdentity(() ->
1450                                         callback.onResult(isSatelliteProvisioned)));
1451                             } else {
1452                                 loge("KEY_SATELLITE_PROVISIONED does not exist.");
1453                                 executor.execute(() -> Binder.withCleanCallingIdentity(() ->
1454                                         callback.onError(new SatelliteException(
1455                                                 SATELLITE_RESULT_REQUEST_FAILED))));
1456                             }
1457                         } else {
1458                             executor.execute(() -> Binder.withCleanCallingIdentity(() ->
1459                                     callback.onError(new SatelliteException(resultCode))));
1460                         }
1461                     }
1462                 };
1463                 telephony.requestIsSatelliteProvisioned(mSubId, receiver);
1464             } else {
1465                 loge("requestIsProvisioned() invalid telephony");
1466                 executor.execute(() -> Binder.withCleanCallingIdentity(() -> callback.onError(
1467                         new SatelliteException(SATELLITE_RESULT_ILLEGAL_STATE))));
1468             }
1469         } catch (RemoteException ex) {
1470             loge("requestIsProvisioned() RemoteException: " + ex);
1471             executor.execute(() -> Binder.withCleanCallingIdentity(() -> callback.onError(
1472                     new SatelliteException(SATELLITE_RESULT_ILLEGAL_STATE))));
1473         }
1474     }
1475 
1476     /**
1477      * Registers for modem state changed from satellite modem.
1478      *
1479      * @param executor The executor on which the callback will be called.
1480      * @param callback The callback to handle the satellite modem state changed event.
1481      *
1482      * @return The {@link SatelliteResult} result of the operation.
1483      *
1484      * @throws SecurityException if the caller doesn't have required permission.
1485      * @throws IllegalStateException if the Telephony process is not currently available.
1486      */
1487     @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
1488     @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
registerForModemStateChanged( @onNull @allbackExecutor Executor executor, @NonNull SatelliteModemStateCallback callback)1489     @SatelliteResult public int registerForModemStateChanged(
1490             @NonNull @CallbackExecutor Executor executor,
1491             @NonNull SatelliteModemStateCallback callback) {
1492         Objects.requireNonNull(executor);
1493         Objects.requireNonNull(callback);
1494 
1495         try {
1496             ITelephony telephony = getITelephony();
1497             if (telephony != null) {
1498                 ISatelliteModemStateCallback internalCallback =
1499                         new ISatelliteModemStateCallback.Stub() {
1500                     @Override
1501                     public void onSatelliteModemStateChanged(int state) {
1502                         executor.execute(() -> Binder.withCleanCallingIdentity(() ->
1503                                 callback.onSatelliteModemStateChanged(state)));
1504                     }
1505                 };
1506                 sSatelliteModemStateCallbackMap.put(callback, internalCallback);
1507                 return telephony.registerForSatelliteModemStateChanged(mSubId, internalCallback);
1508             } else {
1509                 throw new IllegalStateException("telephony service is null.");
1510             }
1511         } catch (RemoteException ex) {
1512             loge("registerForModemStateChanged() RemoteException:" + ex);
1513             ex.rethrowAsRuntimeException();
1514         }
1515         return SATELLITE_RESULT_REQUEST_FAILED;
1516     }
1517 
1518     /**
1519      * Unregisters for modem state changed from satellite modem.
1520      * If callback was not registered before, the request will be ignored.
1521      *
1522      * @param callback The callback that was passed to
1523      * {@link #registerForModemStateChanged(Executor, SatelliteModemStateCallback)}.
1524      *
1525      * @throws SecurityException if the caller doesn't have required permission.
1526      * @throws IllegalStateException if the Telephony process is not currently available.
1527      */
1528     @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
1529     @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
unregisterForModemStateChanged( @onNull SatelliteModemStateCallback callback)1530     public void unregisterForModemStateChanged(
1531             @NonNull SatelliteModemStateCallback callback) {
1532         Objects.requireNonNull(callback);
1533         ISatelliteModemStateCallback internalCallback = sSatelliteModemStateCallbackMap.remove(
1534                 callback);
1535 
1536         try {
1537             ITelephony telephony = getITelephony();
1538             if (telephony != null) {
1539                 if (internalCallback != null) {
1540                     telephony.unregisterForModemStateChanged(mSubId, internalCallback);
1541                 } else {
1542                     loge("unregisterForModemStateChanged: No internal callback.");
1543                 }
1544             } else {
1545                 throw new IllegalStateException("telephony service is null.");
1546             }
1547         } catch (RemoteException ex) {
1548             loge("unregisterForModemStateChanged() RemoteException:" + ex);
1549             ex.rethrowAsRuntimeException();
1550         }
1551     }
1552 
1553     /**
1554      * Register to receive incoming datagrams over satellite.
1555      *
1556      * To poll for pending satellite datagrams, refer to
1557      * {@link #pollPendingDatagrams(Executor, Consumer)}
1558      *
1559      * @param executor The executor on which the callback will be called.
1560      * @param callback The callback to handle incoming datagrams over satellite.
1561      *                 This callback with be invoked when a new datagram is received from satellite.
1562      *
1563      * @return The {@link SatelliteResult} result of the operation.
1564      *
1565      * @throws SecurityException if the caller doesn't have required permission.
1566      * @throws IllegalStateException if the Telephony process is not currently available.
1567      */
1568     @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
1569     @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
registerForIncomingDatagram( @onNull @allbackExecutor Executor executor, @NonNull SatelliteDatagramCallback callback)1570     @SatelliteResult public int registerForIncomingDatagram(
1571             @NonNull @CallbackExecutor Executor executor,
1572             @NonNull SatelliteDatagramCallback callback) {
1573         Objects.requireNonNull(executor);
1574         Objects.requireNonNull(callback);
1575 
1576         try {
1577             ITelephony telephony = getITelephony();
1578             if (telephony != null) {
1579                 ISatelliteDatagramCallback internalCallback =
1580                         new ISatelliteDatagramCallback.Stub() {
1581                             @Override
1582                             public void onSatelliteDatagramReceived(long datagramId,
1583                                     @NonNull SatelliteDatagram datagram, int pendingCount,
1584                                     @NonNull IVoidConsumer internalAck) {
1585                                 Consumer<Void> externalAck = new Consumer<Void>() {
1586                                     @Override
1587                                     public void accept(Void result) {
1588                                         try {
1589                                             internalAck.accept();
1590                                         }  catch (RemoteException e) {
1591                                               logd("onSatelliteDatagramReceived "
1592                                                       + "RemoteException: " + e);
1593                                         }
1594                                     }
1595                                 };
1596 
1597                                 executor.execute(() -> Binder.withCleanCallingIdentity(
1598                                         () -> callback.onSatelliteDatagramReceived(
1599                                                 datagramId, datagram, pendingCount, externalAck)));
1600                             }
1601                         };
1602                 sSatelliteDatagramCallbackMap.put(callback, internalCallback);
1603                 return telephony.registerForIncomingDatagram(mSubId, internalCallback);
1604             } else {
1605                 throw new IllegalStateException("telephony service is null.");
1606             }
1607         } catch (RemoteException ex) {
1608             loge("registerForIncomingDatagram() RemoteException:" + ex);
1609             ex.rethrowAsRuntimeException();
1610         }
1611         return SATELLITE_RESULT_REQUEST_FAILED;
1612     }
1613 
1614     /**
1615      * Unregister to stop receiving incoming datagrams over satellite.
1616      * If callback was not registered before, the request will be ignored.
1617      *
1618      * @param callback The callback that was passed to
1619      * {@link #registerForIncomingDatagram(Executor, SatelliteDatagramCallback)}.
1620      *
1621      * @throws SecurityException if the caller doesn't have required permission.
1622      * @throws IllegalStateException if the Telephony process is not currently available.
1623      */
1624     @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
1625     @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
unregisterForIncomingDatagram(@onNull SatelliteDatagramCallback callback)1626     public void unregisterForIncomingDatagram(@NonNull SatelliteDatagramCallback callback) {
1627         Objects.requireNonNull(callback);
1628         ISatelliteDatagramCallback internalCallback =
1629                 sSatelliteDatagramCallbackMap.remove(callback);
1630 
1631         try {
1632             ITelephony telephony = getITelephony();
1633             if (telephony != null) {
1634                 if (internalCallback != null) {
1635                     telephony.unregisterForIncomingDatagram(mSubId, internalCallback);
1636                 } else {
1637                     loge("unregisterForIncomingDatagram: No internal callback.");
1638                 }
1639             } else {
1640                 throw new IllegalStateException("telephony service is null.");
1641             }
1642         } catch (RemoteException ex) {
1643             loge("unregisterForIncomingDatagram() RemoteException:" + ex);
1644             ex.rethrowAsRuntimeException();
1645         }
1646     }
1647 
1648     /**
1649      * Poll pending satellite datagrams over satellite.
1650      *
1651      * This method should be called when user specifies to check incoming messages over satellite.
1652      * This method requests modem to check if there are any pending datagrams to be received over
1653      * satellite. If there are any incoming datagrams, they will be received via
1654      * {@link SatelliteDatagramCallback#onSatelliteDatagramReceived(long, SatelliteDatagram, int,
1655      * Consumer)} )}
1656      *
1657      * @param executor The executor on which the result listener will be called.
1658      * @param resultListener Listener for the {@link SatelliteResult} result of the operation.
1659      *
1660      * @throws SecurityException if the caller doesn't have required permission.
1661      */
1662     @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
1663     @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
pollPendingDatagrams(@onNull @allbackExecutor Executor executor, @SatelliteResult @NonNull Consumer<Integer> resultListener)1664     public void pollPendingDatagrams(@NonNull @CallbackExecutor Executor executor,
1665             @SatelliteResult @NonNull Consumer<Integer> resultListener) {
1666         Objects.requireNonNull(executor);
1667         Objects.requireNonNull(resultListener);
1668 
1669         try {
1670             ITelephony telephony = getITelephony();
1671             if (telephony != null) {
1672                 IIntegerConsumer internalCallback = new IIntegerConsumer.Stub() {
1673                     @Override
1674                     public void accept(int result) {
1675                         executor.execute(() -> Binder.withCleanCallingIdentity(
1676                                 () -> resultListener.accept(result)));
1677                     }
1678                 };
1679                 telephony.pollPendingDatagrams(mSubId, internalCallback);
1680             } else {
1681                 loge("pollPendingDatagrams() invalid telephony");
1682                 executor.execute(() -> Binder.withCleanCallingIdentity(
1683                         () -> resultListener.accept(SATELLITE_RESULT_ILLEGAL_STATE)));
1684             }
1685         } catch (RemoteException ex) {
1686             loge("pollPendingDatagrams() RemoteException:" + ex);
1687             executor.execute(() -> Binder.withCleanCallingIdentity(
1688                     () -> resultListener.accept(SATELLITE_RESULT_ILLEGAL_STATE)));
1689         }
1690     }
1691 
1692     /**
1693      * Send datagram over satellite.
1694      *
1695      * Gateway encodes SOS message or location sharing message into a datagram and passes it as
1696      * input to this method. Datagram received here will be passed down to modem without any
1697      * encoding or encryption.
1698      *
1699      * @param datagramType datagram type indicating whether the datagram is of type
1700      *                     SOS_SMS or LOCATION_SHARING.
1701      * @param datagram encoded gateway datagram which is encrypted by the caller.
1702      *                 Datagram will be passed down to modem without any encoding or encryption.
1703      * @param needFullScreenPointingUI If set to true, this indicates pointingUI app to open in full
1704      *                                 screen mode if satellite communication needs pointingUI.
1705      *                                 If this is set to false, pointingUI may be presented to the
1706      *                                 user in collapsed view. Application may decide to mark this
1707      *                                 flag as true when the user is sending data for the first time
1708      *                                 or whenever there is a considerable idle time between
1709      *                                 satellite activity. This decision should be done based upon
1710      *                                 user activity and the application's ability to determine the
1711      *                                 best possible UX experience for the user.
1712      * @param executor The executor on which the result 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     @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
1718     @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
sendDatagram(@atagramType int datagramType, @NonNull SatelliteDatagram datagram, boolean needFullScreenPointingUI, @NonNull @CallbackExecutor Executor executor, @SatelliteResult @NonNull Consumer<Integer> resultListener)1719     public void sendDatagram(@DatagramType int datagramType,
1720             @NonNull SatelliteDatagram datagram, boolean needFullScreenPointingUI,
1721             @NonNull @CallbackExecutor Executor executor,
1722             @SatelliteResult @NonNull Consumer<Integer> resultListener) {
1723         Objects.requireNonNull(datagram);
1724         Objects.requireNonNull(executor);
1725         Objects.requireNonNull(resultListener);
1726 
1727         try {
1728             ITelephony telephony = getITelephony();
1729             if (telephony != null) {
1730                 IIntegerConsumer internalCallback = new IIntegerConsumer.Stub() {
1731                     @Override
1732                     public void accept(int result) {
1733                         executor.execute(() -> Binder.withCleanCallingIdentity(
1734                                 () -> resultListener.accept(result)));
1735                     }
1736                 };
1737                 telephony.sendDatagram(mSubId, datagramType, datagram,
1738                         needFullScreenPointingUI, internalCallback);
1739             } else {
1740                 loge("sendDatagram() invalid telephony");
1741                 executor.execute(() -> Binder.withCleanCallingIdentity(
1742                         () -> resultListener.accept(SATELLITE_RESULT_ILLEGAL_STATE)));
1743             }
1744         } catch (RemoteException ex) {
1745             loge("sendDatagram() RemoteException:" + ex);
1746             executor.execute(() -> Binder.withCleanCallingIdentity(
1747                     () -> resultListener.accept(SATELLITE_RESULT_ILLEGAL_STATE)));
1748         }
1749     }
1750 
1751     /**
1752      * Request to get whether satellite communication is allowed for the current location.
1753      *
1754      * @param executor The executor on which the callback will be called.
1755      * @param callback The callback object to which the result will be delivered.
1756      *                 If the request is successful, {@link OutcomeReceiver#onResult(Object)}
1757      *                 will return a {@code boolean} with value {@code true} if satellite
1758      *                 communication is allowed for the current location and
1759      *                 {@code false} otherwise.
1760      *                 If the request is not successful, {@link OutcomeReceiver#onError(Throwable)}
1761      *                 will return a {@link SatelliteException} with the {@link SatelliteResult}.
1762      *
1763      * @throws SecurityException if the caller doesn't have required permission.
1764      */
1765     @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
1766     @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
requestIsCommunicationAllowedForCurrentLocation( @onNull @allbackExecutor Executor executor, @NonNull OutcomeReceiver<Boolean, SatelliteException> callback)1767     public void requestIsCommunicationAllowedForCurrentLocation(
1768             @NonNull @CallbackExecutor Executor executor,
1769             @NonNull OutcomeReceiver<Boolean, SatelliteException> callback) {
1770         Objects.requireNonNull(executor);
1771         Objects.requireNonNull(callback);
1772 
1773         try {
1774             ITelephony telephony = getITelephony();
1775             if (telephony != null) {
1776                 ResultReceiver receiver = new ResultReceiver(null) {
1777                     @Override
1778                     protected void onReceiveResult(int resultCode, Bundle resultData) {
1779                         if (resultCode == SATELLITE_RESULT_SUCCESS) {
1780                             if (resultData.containsKey(KEY_SATELLITE_COMMUNICATION_ALLOWED)) {
1781                                 boolean isSatelliteCommunicationAllowed =
1782                                         resultData.getBoolean(KEY_SATELLITE_COMMUNICATION_ALLOWED);
1783                                 executor.execute(() -> Binder.withCleanCallingIdentity(() ->
1784                                         callback.onResult(isSatelliteCommunicationAllowed)));
1785                             } else {
1786                                 loge("KEY_SATELLITE_COMMUNICATION_ALLOWED does not exist.");
1787                                 executor.execute(() -> Binder.withCleanCallingIdentity(() ->
1788                                         callback.onError(new SatelliteException(
1789                                                 SATELLITE_RESULT_REQUEST_FAILED))));
1790                             }
1791                         } else {
1792                             executor.execute(() -> Binder.withCleanCallingIdentity(() ->
1793                                     callback.onError(new SatelliteException(resultCode))));
1794                         }
1795                     }
1796                 };
1797                 telephony.requestIsCommunicationAllowedForCurrentLocation(mSubId, receiver);
1798             } else {
1799                 loge("requestIsCommunicationAllowedForCurrentLocation() invalid telephony");
1800                 executor.execute(() -> Binder.withCleanCallingIdentity(() -> callback.onError(
1801                         new SatelliteException(SATELLITE_RESULT_ILLEGAL_STATE))));
1802             }
1803         } catch (RemoteException ex) {
1804             loge("requestIsCommunicationAllowedForCurrentLocation() RemoteException: " + ex);
1805             executor.execute(() -> Binder.withCleanCallingIdentity(() -> callback.onError(
1806                     new SatelliteException(SATELLITE_RESULT_ILLEGAL_STATE))));
1807         }
1808     }
1809 
1810     /**
1811      * Request to get the duration in seconds after which the satellite will be visible.
1812      * This will be {@link Duration#ZERO} if the satellite is currently visible.
1813      *
1814      * @param executor The executor on which the callback will be called.
1815      * @param callback The callback object to which the result will be delivered.
1816      *                 If the request is successful, {@link OutcomeReceiver#onResult(Object)}
1817      *                 will return the time after which the satellite will be visible.
1818      *                 If the request is not successful, {@link OutcomeReceiver#onError(Throwable)}
1819      *                 will return a {@link SatelliteException} with the {@link SatelliteResult}.
1820      *
1821      * @throws SecurityException if the caller doesn't have required permission.
1822      */
1823     @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
1824     @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
requestTimeForNextSatelliteVisibility(@onNull @allbackExecutor Executor executor, @NonNull OutcomeReceiver<Duration, SatelliteException> callback)1825     public void requestTimeForNextSatelliteVisibility(@NonNull @CallbackExecutor Executor executor,
1826             @NonNull OutcomeReceiver<Duration, SatelliteException> callback) {
1827         Objects.requireNonNull(executor);
1828         Objects.requireNonNull(callback);
1829 
1830         try {
1831             ITelephony telephony = getITelephony();
1832             if (telephony != null) {
1833                 ResultReceiver receiver = new ResultReceiver(null) {
1834                     @Override
1835                     protected void onReceiveResult(int resultCode, Bundle resultData) {
1836                         if (resultCode == SATELLITE_RESULT_SUCCESS) {
1837                             if (resultData.containsKey(KEY_SATELLITE_NEXT_VISIBILITY)) {
1838                                 int nextVisibilityDuration =
1839                                         resultData.getInt(KEY_SATELLITE_NEXT_VISIBILITY);
1840                                 executor.execute(() -> Binder.withCleanCallingIdentity(() ->
1841                                         callback.onResult(
1842                                                 Duration.ofSeconds(nextVisibilityDuration))));
1843                             } else {
1844                                 loge("KEY_SATELLITE_NEXT_VISIBILITY does not exist.");
1845                                 executor.execute(() -> Binder.withCleanCallingIdentity(() ->
1846                                         callback.onError(new SatelliteException(
1847                                                 SATELLITE_RESULT_REQUEST_FAILED))));
1848                             }
1849                         } else {
1850                             executor.execute(() -> Binder.withCleanCallingIdentity(() ->
1851                                     callback.onError(new SatelliteException(resultCode))));
1852                         }
1853                     }
1854                 };
1855                 telephony.requestTimeForNextSatelliteVisibility(mSubId, receiver);
1856             } else {
1857                 loge("requestTimeForNextSatelliteVisibility() invalid telephony");
1858                 executor.execute(() -> Binder.withCleanCallingIdentity(() -> callback.onError(
1859                         new SatelliteException(SATELLITE_RESULT_ILLEGAL_STATE))));
1860             }
1861         } catch (RemoteException ex) {
1862             loge("requestTimeForNextSatelliteVisibility() RemoteException: " + ex);
1863             executor.execute(() -> Binder.withCleanCallingIdentity(() -> callback.onError(
1864                     new SatelliteException(SATELLITE_RESULT_ILLEGAL_STATE))));
1865         }
1866     }
1867 
1868     /**
1869      * Inform whether the device is aligned with the satellite for demo mode.
1870      *
1871      * Framework can send datagram to modem only when device is aligned with the satellite.
1872      * This method helps framework to simulate the experience of sending datagram over satellite.
1873      *
1874      * @param isAligned {@true} Device is aligned with the satellite for demo mode
1875      *                  {@false} Device is not aligned with the satellite for demo mode
1876      *
1877      * @throws SecurityException if the caller doesn't have required permission.
1878      * @throws IllegalStateException if the Telephony process is not currently available.
1879      */
1880     @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
1881     @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
setDeviceAlignedWithSatellite(boolean isAligned)1882     public void setDeviceAlignedWithSatellite(boolean isAligned) {
1883         try {
1884             ITelephony telephony = getITelephony();
1885             if (telephony != null) {
1886                 telephony.setDeviceAlignedWithSatellite(mSubId, isAligned);
1887             } else {
1888                 throw new IllegalStateException("telephony service is null.");
1889             }
1890         } catch (RemoteException ex) {
1891             loge("setDeviceAlignedWithSatellite() RemoteException:" + ex);
1892             ex.rethrowAsRuntimeException();
1893         }
1894     }
1895 
1896     /**
1897      * User request to enable or disable carrier supported satellite plmn scan and attach by modem.
1898      * <p>
1899      * This API should be called by only settings app to pass down the user input for
1900      * enabling/disabling satellite. This user input will be persisted across device reboots.
1901      * <p>
1902      * Satellite will be enabled only when the following conditions are met:
1903      * <ul>
1904      * <li>Users want to enable it.</li>
1905      * <li>There is no satellite communication restriction, which is added by
1906      * {@link #addAttachRestrictionForCarrier(int, int, Executor, Consumer)}</li>
1907      * <li>The carrier config {@link
1908      * android.telephony.CarrierConfigManager#KEY_SATELLITE_ATTACH_SUPPORTED_BOOL} is set to
1909      * {@code true}.</li>
1910      * </ul>
1911      *
1912      * @param subId The subscription ID of the carrier.
1913      * @param enableSatellite {@code true} to enable the satellite and {@code false} to disable.
1914      * @param executor The executor on which the error code listener will be called.
1915      * @param resultListener Listener for the {@link SatelliteResult} result of the operation.
1916      *
1917      * @throws SecurityException if the caller doesn't have required permission.
1918      * @throws IllegalArgumentException if the subscription is invalid.
1919      */
1920     @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
1921     @FlaggedApi(Flags.FLAG_CARRIER_ENABLED_SATELLITE_FLAG)
requestAttachEnabledForCarrier(int subId, boolean enableSatellite, @NonNull @CallbackExecutor Executor executor, @SatelliteResult @NonNull Consumer<Integer> resultListener)1922     public void requestAttachEnabledForCarrier(int subId, boolean enableSatellite,
1923             @NonNull @CallbackExecutor Executor executor,
1924             @SatelliteResult @NonNull Consumer<Integer> resultListener) {
1925         Objects.requireNonNull(executor);
1926         Objects.requireNonNull(resultListener);
1927 
1928         if (enableSatellite) {
1929             removeAttachRestrictionForCarrier(subId,
1930                     SATELLITE_COMMUNICATION_RESTRICTION_REASON_USER, executor, resultListener);
1931         } else {
1932             addAttachRestrictionForCarrier(subId,
1933                     SATELLITE_COMMUNICATION_RESTRICTION_REASON_USER, executor, resultListener);
1934         }
1935     }
1936 
1937     /**
1938      * Request to get whether the carrier supported satellite plmn scan and attach by modem is
1939      * enabled by user.
1940      *
1941      * @param subId The subscription ID of the carrier.
1942      * @param executor The executor on which the callback will be called.
1943      * @param callback The callback object to which the result will be delivered.
1944      *                 If the request is successful, {@link OutcomeReceiver#onResult(Object)}
1945      *                 will return a {@code boolean} with value {@code true} if the satellite
1946      *                 is enabled and {@code false} otherwise.
1947      *                 If the request is not successful, {@link OutcomeReceiver#onError(Throwable)}
1948      *                 will return a {@link SatelliteException} with the {@link SatelliteResult}.
1949      *
1950      * @throws SecurityException if the caller doesn't have required permission.
1951      * @throws IllegalStateException if the Telephony process is not currently available.
1952      * @throws IllegalArgumentException if the subscription is invalid.
1953      */
1954     @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
1955     @FlaggedApi(Flags.FLAG_CARRIER_ENABLED_SATELLITE_FLAG)
requestIsAttachEnabledForCarrier(int subId, @NonNull @CallbackExecutor Executor executor, @NonNull OutcomeReceiver<Boolean, SatelliteException> callback)1956     public void requestIsAttachEnabledForCarrier(int subId,
1957             @NonNull @CallbackExecutor Executor executor,
1958             @NonNull OutcomeReceiver<Boolean, SatelliteException> callback) {
1959         Objects.requireNonNull(executor);
1960         Objects.requireNonNull(callback);
1961 
1962         Set<Integer> restrictionReason = getAttachRestrictionReasonsForCarrier(subId);
1963         executor.execute(() -> callback.onResult(
1964                 !restrictionReason.contains(SATELLITE_COMMUNICATION_RESTRICTION_REASON_USER)));
1965     }
1966 
1967     /**
1968      * Add a restriction reason for disallowing carrier supported satellite plmn scan and attach
1969      * by modem.
1970      *
1971      * @param subId The subscription ID of the carrier.
1972      * @param reason Reason for disallowing satellite communication.
1973      * @param executor The executor on which the error code listener will be called.
1974      * @param resultListener Listener for the {@link SatelliteResult} result of the operation.
1975      *
1976      * @throws SecurityException if the caller doesn't have required permission.
1977      * @throws IllegalArgumentException if the subscription is invalid.
1978      */
1979     @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
1980     @FlaggedApi(Flags.FLAG_CARRIER_ENABLED_SATELLITE_FLAG)
addAttachRestrictionForCarrier(int subId, @SatelliteCommunicationRestrictionReason int reason, @NonNull @CallbackExecutor Executor executor, @SatelliteResult @NonNull Consumer<Integer> resultListener)1981     public void addAttachRestrictionForCarrier(int subId,
1982             @SatelliteCommunicationRestrictionReason int reason,
1983             @NonNull @CallbackExecutor Executor executor,
1984             @SatelliteResult @NonNull Consumer<Integer> resultListener) {
1985         if (!SubscriptionManager.isValidSubscriptionId(subId)) {
1986             throw new IllegalArgumentException("Invalid subscription ID");
1987         }
1988 
1989         try {
1990             ITelephony telephony = getITelephony();
1991             if (telephony != null) {
1992                 IIntegerConsumer errorCallback = new IIntegerConsumer.Stub() {
1993                     @Override
1994                     public void accept(int result) {
1995                         executor.execute(() -> Binder.withCleanCallingIdentity(
1996                                 () -> resultListener.accept(result)));
1997                     }
1998                 };
1999                 telephony.addAttachRestrictionForCarrier(subId, reason, errorCallback);
2000             } else {
2001                 loge("addAttachRestrictionForCarrier() invalid telephony");
2002                 executor.execute(() -> Binder.withCleanCallingIdentity(
2003                         () -> resultListener.accept(SATELLITE_RESULT_ILLEGAL_STATE)));
2004             }
2005         } catch (RemoteException ex) {
2006             loge("addAttachRestrictionForCarrier() RemoteException:" + ex);
2007             executor.execute(() -> Binder.withCleanCallingIdentity(
2008                     () -> resultListener.accept(SATELLITE_RESULT_ILLEGAL_STATE)));
2009         }
2010     }
2011 
2012     /**
2013      * Remove a restriction reason for disallowing carrier supported satellite plmn scan and attach
2014      * by modem.
2015      *
2016      * @param subId The subscription ID of the carrier.
2017      * @param reason Reason for disallowing satellite communication.
2018      * @param executor The executor on which the error code listener will be called.
2019      * @param resultListener Listener for the {@link SatelliteResult} result of the operation.
2020      *
2021      * @throws SecurityException if the caller doesn't have required permission.
2022      * @throws IllegalArgumentException if the subscription is invalid.
2023      */
2024     @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
2025     @FlaggedApi(Flags.FLAG_CARRIER_ENABLED_SATELLITE_FLAG)
removeAttachRestrictionForCarrier(int subId, @SatelliteCommunicationRestrictionReason int reason, @NonNull @CallbackExecutor Executor executor, @SatelliteResult @NonNull Consumer<Integer> resultListener)2026     public void removeAttachRestrictionForCarrier(int subId,
2027             @SatelliteCommunicationRestrictionReason int reason,
2028             @NonNull @CallbackExecutor Executor executor,
2029             @SatelliteResult @NonNull Consumer<Integer> resultListener) {
2030         if (!SubscriptionManager.isValidSubscriptionId(subId)) {
2031             throw new IllegalArgumentException("Invalid subscription ID");
2032         }
2033 
2034         try {
2035             ITelephony telephony = getITelephony();
2036             if (telephony != null) {
2037                 IIntegerConsumer errorCallback = new IIntegerConsumer.Stub() {
2038                     @Override
2039                     public void accept(int result) {
2040                         executor.execute(() -> Binder.withCleanCallingIdentity(
2041                                 () -> resultListener.accept(result)));
2042                     }
2043                 };
2044                 telephony.removeAttachRestrictionForCarrier(subId, reason, errorCallback);
2045             } else {
2046                 loge("removeAttachRestrictionForCarrier() invalid telephony");
2047                 executor.execute(() -> Binder.withCleanCallingIdentity(
2048                         () -> resultListener.accept(SATELLITE_RESULT_ILLEGAL_STATE)));
2049             }
2050         } catch (RemoteException ex) {
2051             loge("removeAttachRestrictionForCarrier() RemoteException:" + ex);
2052             executor.execute(() -> Binder.withCleanCallingIdentity(
2053                     () -> resultListener.accept(SATELLITE_RESULT_ILLEGAL_STATE)));
2054         }
2055     }
2056 
2057     /**
2058      * Get reasons for disallowing satellite attach, as requested by
2059      * {@link #addAttachRestrictionForCarrier(int, int, Executor, Consumer)}
2060      *
2061      * @param subId The subscription ID of the carrier.
2062      * @return Set of reasons for disallowing satellite communication.
2063      *
2064      * @throws SecurityException if the caller doesn't have required permission.
2065      * @throws IllegalStateException if the Telephony process is not currently available.
2066      * @throws IllegalArgumentException if the subscription is invalid.
2067      */
2068     @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
2069     @SatelliteCommunicationRestrictionReason
2070     @FlaggedApi(Flags.FLAG_CARRIER_ENABLED_SATELLITE_FLAG)
getAttachRestrictionReasonsForCarrier(int subId)2071     @NonNull public Set<Integer> getAttachRestrictionReasonsForCarrier(int subId) {
2072         if (!SubscriptionManager.isValidSubscriptionId(subId)) {
2073             throw new IllegalArgumentException("Invalid subscription ID");
2074         }
2075 
2076         try {
2077             ITelephony telephony = getITelephony();
2078             if (telephony != null) {
2079                 int[] receivedArray =
2080                         telephony.getAttachRestrictionReasonsForCarrier(subId);
2081                 if (receivedArray.length == 0) {
2082                     logd("receivedArray is empty, create empty set");
2083                     return new HashSet<>();
2084                 } else {
2085                     return Arrays.stream(receivedArray).boxed().collect(Collectors.toSet());
2086                 }
2087             } else {
2088                 throw new IllegalStateException("Telephony service is null.");
2089             }
2090         } catch (RemoteException ex) {
2091             loge("getAttachRestrictionReasonsForCarrier() RemoteException: " + ex);
2092             ex.rethrowAsRuntimeException();
2093         }
2094         return new HashSet<>();
2095     }
2096 
2097     /**
2098      * Request to get the signal strength of the satellite connection.
2099      *
2100      * <p>
2101      * Note: This API is specifically designed for OEM enabled satellite connectivity only.
2102      * For satellite connectivity enabled using carrier roaming, please refer to
2103      * {@link android.telephony.TelephonyCallback.SignalStrengthsListener}, and
2104      * {@link TelephonyManager#registerTelephonyCallback(Executor, TelephonyCallback)}.
2105      * </p>
2106      *
2107      * @param executor The executor on which the callback will be called.
2108      * @param callback The callback object to which the result will be delivered. If the request is
2109      * successful, {@link OutcomeReceiver#onResult(Object)} will return an instance of
2110      * {@link NtnSignalStrength} with a value of {@link NtnSignalStrength.NtnSignalStrengthLevel}
2111      * The {@link NtnSignalStrength#NTN_SIGNAL_STRENGTH_NONE} will be returned if there is no
2112      * signal strength data available.
2113      * If the request is not successful, {@link OutcomeReceiver#onError(Throwable)} will return a
2114      * {@link SatelliteException} with the {@link SatelliteResult}.
2115      *
2116      * @throws SecurityException if the caller doesn't have required permission.
2117      */
2118     @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
2119     @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
requestNtnSignalStrength(@onNull @allbackExecutor Executor executor, @NonNull OutcomeReceiver<NtnSignalStrength, SatelliteException> callback)2120     public void requestNtnSignalStrength(@NonNull @CallbackExecutor Executor executor,
2121             @NonNull OutcomeReceiver<NtnSignalStrength, SatelliteException> callback) {
2122         Objects.requireNonNull(executor);
2123         Objects.requireNonNull(callback);
2124 
2125         try {
2126             ITelephony telephony = getITelephony();
2127             if (telephony != null) {
2128                 ResultReceiver receiver = new ResultReceiver(null) {
2129                     @Override
2130                     protected void onReceiveResult(int resultCode, Bundle resultData) {
2131                         if (resultCode == SATELLITE_RESULT_SUCCESS) {
2132                             if (resultData.containsKey(KEY_NTN_SIGNAL_STRENGTH)) {
2133                                 NtnSignalStrength ntnSignalStrength =
2134                                         resultData.getParcelable(KEY_NTN_SIGNAL_STRENGTH,
2135                                                 NtnSignalStrength.class);
2136                                 executor.execute(() -> Binder.withCleanCallingIdentity(() ->
2137                                         callback.onResult(ntnSignalStrength)));
2138                             } else {
2139                                 loge("KEY_NTN_SIGNAL_STRENGTH does not exist.");
2140                                 executor.execute(() -> Binder.withCleanCallingIdentity(() ->
2141                                         callback.onError(new SatelliteException(
2142                                                 SATELLITE_RESULT_REQUEST_FAILED))));
2143                             }
2144                         } else {
2145                             executor.execute(() -> Binder.withCleanCallingIdentity(() ->
2146                                     callback.onError(new SatelliteException(resultCode))));
2147                         }
2148                     }
2149                 };
2150                 telephony.requestNtnSignalStrength(mSubId, receiver);
2151             } else {
2152                 loge("requestNtnSignalStrength() invalid telephony");
2153                 executor.execute(() -> Binder.withCleanCallingIdentity(() -> callback.onError(
2154                         new SatelliteException(SATELLITE_RESULT_ILLEGAL_STATE))));
2155             }
2156         } catch (RemoteException ex) {
2157             loge("requestNtnSignalStrength() RemoteException: " + ex);
2158             executor.execute(() -> Binder.withCleanCallingIdentity(() -> callback.onError(
2159                     new SatelliteException(SATELLITE_RESULT_ILLEGAL_STATE))));
2160         }
2161     }
2162 
2163     /**
2164      * Registers for NTN signal strength changed from satellite modem.
2165      * If the registration operation is not successful, a {@link SatelliteException} that contains
2166      * {@link SatelliteResult} will be thrown.
2167      *
2168      * <p>
2169      * Note: This API is specifically designed for OEM enabled satellite connectivity only.
2170      * For satellite connectivity enabled using carrier roaming, please refer to
2171      * {@link android.telephony.TelephonyCallback.SignalStrengthsListener}, and
2172      * {@link TelephonyManager#registerTelephonyCallback(Executor, TelephonyCallback)}.
2173      * </p>
2174      *
2175      * @param executor The executor on which the callback will be called.
2176      * @param callback The callback to handle the NTN signal strength changed event.
2177      *
2178      * @throws SecurityException if the caller doesn't have required permission.
2179      * @throws IllegalStateException if the Telephony process is not currently available.
2180      */
2181     @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
2182     @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
registerForNtnSignalStrengthChanged(@onNull @allbackExecutor Executor executor, @NonNull NtnSignalStrengthCallback callback)2183     public void registerForNtnSignalStrengthChanged(@NonNull @CallbackExecutor Executor executor,
2184             @NonNull NtnSignalStrengthCallback callback) {
2185         Objects.requireNonNull(executor);
2186         Objects.requireNonNull(callback);
2187 
2188         try {
2189             ITelephony telephony = getITelephony();
2190             if (telephony != null) {
2191                 INtnSignalStrengthCallback internalCallback =
2192                         new INtnSignalStrengthCallback.Stub() {
2193                             @Override
2194                             public void onNtnSignalStrengthChanged(
2195                                     NtnSignalStrength ntnSignalStrength) {
2196                                 executor.execute(() -> Binder.withCleanCallingIdentity(
2197                                         () -> callback.onNtnSignalStrengthChanged(
2198                                                 ntnSignalStrength)));
2199                             }
2200                         };
2201                 telephony.registerForNtnSignalStrengthChanged(mSubId, internalCallback);
2202                 sNtnSignalStrengthCallbackMap.put(callback, internalCallback);
2203             } else {
2204                 throw new IllegalStateException("Telephony service is null.");
2205             }
2206         } catch (RemoteException ex) {
2207             loge("registerForNtnSignalStrengthChanged() RemoteException: " + ex);
2208             ex.rethrowAsRuntimeException();
2209         }
2210     }
2211 
2212     /**
2213      * Unregisters for NTN signal strength changed from satellite modem.
2214      * If callback was not registered before, the request will be ignored.
2215      *
2216      * <p>
2217      * Note: This API is specifically designed for OEM enabled satellite connectivity only.
2218      * For satellite connectivity enabled using carrier roaming, please refer to
2219      * {@link TelephonyManager#unregisterTelephonyCallback(TelephonyCallback)}..
2220      * </p>
2221      *
2222      * @param callback The callback that was passed to.
2223      * {@link #registerForNtnSignalStrengthChanged(Executor, NtnSignalStrengthCallback)}.
2224      *
2225      * @throws SecurityException if the caller doesn't have required permission.
2226      * @throws IllegalArgumentException if the callback is not valid or has already been
2227      * unregistered.
2228      * @throws IllegalStateException if the Telephony process is not currently available.
2229      */
2230     @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
2231     @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
unregisterForNtnSignalStrengthChanged(@onNull NtnSignalStrengthCallback callback)2232     public void unregisterForNtnSignalStrengthChanged(@NonNull NtnSignalStrengthCallback callback) {
2233         Objects.requireNonNull(callback);
2234         INtnSignalStrengthCallback internalCallback =
2235                 sNtnSignalStrengthCallbackMap.remove(callback);
2236 
2237         try {
2238             ITelephony telephony = getITelephony();
2239             if (telephony != null) {
2240                 if (internalCallback != null) {
2241                     telephony.unregisterForNtnSignalStrengthChanged(mSubId, internalCallback);
2242                 } else {
2243                     loge("unregisterForNtnSignalStrengthChanged: No internal callback.");
2244                     throw new IllegalArgumentException("callback is not valid");
2245                 }
2246             } else {
2247                 throw new IllegalStateException("Telephony service is null.");
2248             }
2249         } catch (RemoteException ex) {
2250             loge("unregisterForNtnSignalStrengthChanged() RemoteException: " + ex);
2251             ex.rethrowAsRuntimeException();
2252         }
2253     }
2254 
2255     /**
2256      * Registers for satellite capabilities change event from the satellite service.
2257      *
2258      * @param executor The executor on which the callback will be called.
2259      * @param callback The callback to handle the satellite capabilities changed event.
2260      *
2261      * @throws SecurityException if the caller doesn't have required permission.
2262      * @throws IllegalStateException if the Telephony process is not currently available.
2263      */
2264     @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
2265     @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
registerForCapabilitiesChanged( @onNull @allbackExecutor Executor executor, @NonNull SatelliteCapabilitiesCallback callback)2266     @SatelliteResult public int registerForCapabilitiesChanged(
2267             @NonNull @CallbackExecutor Executor executor,
2268             @NonNull SatelliteCapabilitiesCallback callback) {
2269         Objects.requireNonNull(executor);
2270         Objects.requireNonNull(callback);
2271 
2272         try {
2273             ITelephony telephony = getITelephony();
2274             if (telephony != null) {
2275                 ISatelliteCapabilitiesCallback internalCallback =
2276                         new ISatelliteCapabilitiesCallback.Stub() {
2277                             @Override
2278                             public void onSatelliteCapabilitiesChanged(
2279                                     SatelliteCapabilities capabilities) {
2280                                 executor.execute(() -> Binder.withCleanCallingIdentity(
2281                                         () -> callback.onSatelliteCapabilitiesChanged(
2282                                                 capabilities)));
2283                             }
2284                         };
2285                 sSatelliteCapabilitiesCallbackMap.put(callback, internalCallback);
2286                 return telephony.registerForCapabilitiesChanged(mSubId, internalCallback);
2287             } else {
2288                 throw new IllegalStateException("Telephony service is null.");
2289             }
2290         } catch (RemoteException ex) {
2291             loge("registerForCapabilitiesChanged() RemoteException: " + ex);
2292             ex.rethrowAsRuntimeException();
2293         }
2294         return SATELLITE_RESULT_REQUEST_FAILED;
2295     }
2296 
2297     /**
2298      * Unregisters for satellite capabilities change event from the satellite service.
2299      * If callback was not registered before, the request will be ignored.
2300      *
2301      * @param callback The callback that was passed to.
2302      * {@link #registerForCapabilitiesChanged(Executor, SatelliteCapabilitiesCallback)}.
2303      *
2304      * @throws SecurityException if the caller doesn't have required permission.
2305      * @throws IllegalStateException if the Telephony process is not currently available.
2306      */
2307     @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
2308     @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
unregisterForCapabilitiesChanged( @onNull SatelliteCapabilitiesCallback callback)2309     public void unregisterForCapabilitiesChanged(
2310             @NonNull SatelliteCapabilitiesCallback callback) {
2311         Objects.requireNonNull(callback);
2312         ISatelliteCapabilitiesCallback internalCallback =
2313                 sSatelliteCapabilitiesCallbackMap.remove(callback);
2314 
2315         try {
2316             ITelephony telephony = getITelephony();
2317             if (telephony != null) {
2318                 if (internalCallback != null) {
2319                     telephony.unregisterForCapabilitiesChanged(mSubId, internalCallback);
2320                 } else {
2321                     loge("unregisterForCapabilitiesChanged: No internal callback.");
2322                 }
2323             } else {
2324                 throw new IllegalStateException("Telephony service is null.");
2325             }
2326         } catch (RemoteException ex) {
2327             loge("unregisterForCapabilitiesChanged() RemoteException: " + ex);
2328             ex.rethrowAsRuntimeException();
2329         }
2330     }
2331 
2332     /**
2333      * Get all satellite PLMNs for which attach is enable for carrier.
2334      *
2335      * @param subId subId The subscription ID of the carrier.
2336      *
2337      * @return List of plmn for carrier satellite service. If no plmn is available, empty list will
2338      * be returned.
2339      */
2340     @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
2341     @FlaggedApi(Flags.FLAG_CARRIER_ENABLED_SATELLITE_FLAG)
getSatellitePlmnsForCarrier(int subId)2342     @NonNull public List<String> getSatellitePlmnsForCarrier(int subId) {
2343         if (!SubscriptionManager.isValidSubscriptionId(subId)) {
2344             throw new IllegalArgumentException("Invalid subscription ID");
2345         }
2346 
2347         try {
2348             ITelephony telephony = getITelephony();
2349             if (telephony != null) {
2350                 return telephony.getSatellitePlmnsForCarrier(subId);
2351             } else {
2352                 throw new IllegalStateException("Telephony service is null.");
2353             }
2354         } catch (RemoteException ex) {
2355             loge("getSatellitePlmnsForCarrier() RemoteException: " + ex);
2356             ex.rethrowAsRuntimeException();
2357         }
2358         return new ArrayList<>();
2359     }
2360 
2361     /**
2362      * Registers for the satellite supported state changed.
2363      *
2364      * @param executor The executor on which the callback will be called.
2365      * @param callback The callback to handle the satellite supoprted state changed event.
2366      *
2367      * @return The {@link SatelliteResult} result of the operation.
2368      *
2369      * @throws SecurityException if the caller doesn't have required permission.
2370      * @throws IllegalStateException if the Telephony process is not currently available.
2371      *
2372      * @hide
2373      */
2374     @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
registerForSupportedStateChanged( @onNull @allbackExecutor Executor executor, @NonNull SatelliteSupportedStateCallback callback)2375     @SatelliteResult public int registerForSupportedStateChanged(
2376             @NonNull @CallbackExecutor Executor executor,
2377             @NonNull SatelliteSupportedStateCallback callback) {
2378         Objects.requireNonNull(executor);
2379         Objects.requireNonNull(callback);
2380 
2381         try {
2382             ITelephony telephony = getITelephony();
2383             if (telephony != null) {
2384                 ISatelliteSupportedStateCallback internalCallback =
2385                         new ISatelliteSupportedStateCallback.Stub() {
2386                             @Override
2387                             public void onSatelliteSupportedStateChanged(boolean supported) {
2388                                 executor.execute(() -> Binder.withCleanCallingIdentity(
2389                                         () -> callback.onSatelliteSupportedStateChanged(
2390                                                 supported)));
2391                             }
2392                         };
2393                 sSatelliteSupportedStateCallbackMap.put(callback, internalCallback);
2394                 return telephony.registerForSatelliteSupportedStateChanged(
2395                         mSubId, internalCallback);
2396             } else {
2397                 throw new IllegalStateException("telephony service is null.");
2398             }
2399         } catch (RemoteException ex) {
2400             loge("registerForSupportedStateChanged() RemoteException: " + ex);
2401             ex.rethrowAsRuntimeException();
2402         }
2403         return SATELLITE_RESULT_REQUEST_FAILED;
2404     }
2405 
2406     /**
2407      * Unregisters for the satellite supported state changed.
2408      * If callback was not registered before, the request will be ignored.
2409      *
2410      * @param callback The callback that was passed to
2411      * {@link #registerForSupportedStateChanged(Executor, SatelliteSupportedStateCallback)}
2412      *
2413      * @throws SecurityException if the caller doesn't have required permission.
2414      * @throws IllegalStateException if the Telephony process is not currently available.
2415      *
2416      * @hide
2417      */
2418     @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
2419     @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
unregisterForSupportedStateChanged( @onNull SatelliteSupportedStateCallback callback)2420     public void unregisterForSupportedStateChanged(
2421             @NonNull SatelliteSupportedStateCallback callback) {
2422         Objects.requireNonNull(callback);
2423         ISatelliteSupportedStateCallback internalCallback =
2424                 sSatelliteSupportedStateCallbackMap.remove(callback);
2425 
2426         try {
2427             ITelephony telephony = getITelephony();
2428             if (telephony != null) {
2429                 if (internalCallback != null) {
2430                     telephony.unregisterForSatelliteSupportedStateChanged(mSubId, internalCallback);
2431                 } else {
2432                     loge("unregisterForSupportedStateChanged: No internal callback.");
2433                 }
2434             } else {
2435                 throw new IllegalStateException("telephony service is null.");
2436             }
2437         } catch (RemoteException ex) {
2438             loge("unregisterForSupportedStateChanged() RemoteException: " + ex);
2439             ex.rethrowAsRuntimeException();
2440         }
2441     }
2442 
2443     /**
2444      * Registers for the satellite communication allowed state changed.
2445      *
2446      * @param executor The executor on which the callback will be called.
2447      * @param callback The callback to handle satellite communication allowed state changed event.
2448      * @return The {@link SatelliteResult} result of the operation.
2449      * @throws SecurityException     if the caller doesn't have required permission.
2450      * @throws IllegalStateException if the Telephony process is not currently available.
2451      * @hide
2452      */
2453     @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
2454     @SatelliteResult
registerForCommunicationAllowedStateChanged( @onNull @allbackExecutor Executor executor, @NonNull SatelliteCommunicationAllowedStateCallback callback)2455     public int registerForCommunicationAllowedStateChanged(
2456             @NonNull @CallbackExecutor Executor executor,
2457             @NonNull SatelliteCommunicationAllowedStateCallback callback) {
2458         Objects.requireNonNull(executor);
2459         Objects.requireNonNull(callback);
2460 
2461         try {
2462             ITelephony telephony = getITelephony();
2463             if (telephony != null) {
2464                 ISatelliteCommunicationAllowedStateCallback internalCallback =
2465                         new ISatelliteCommunicationAllowedStateCallback.Stub() {
2466                             @Override
2467                             public void onSatelliteCommunicationAllowedStateChanged(
2468                                     boolean isAllowed) {
2469                                 executor.execute(() -> Binder.withCleanCallingIdentity(
2470                                         () -> callback.onSatelliteCommunicationAllowedStateChanged(
2471                                                 isAllowed)));
2472                             }
2473                         };
2474                 sSatelliteCommunicationAllowedStateCallbackMap.put(callback, internalCallback);
2475                 return telephony.registerForCommunicationAllowedStateChanged(
2476                         mSubId, internalCallback);
2477             } else {
2478                 throw new IllegalStateException("telephony service is null.");
2479             }
2480         } catch (RemoteException ex) {
2481             loge("registerForCommunicationAllowedStateChanged() RemoteException: " + ex);
2482             ex.rethrowAsRuntimeException();
2483         }
2484         return SATELLITE_RESULT_REQUEST_FAILED;
2485     }
2486 
2487     /**
2488      * Unregisters for the satellite communication allowed state changed.
2489      * If callback was not registered before, the request will be ignored.
2490      *
2491      * @param callback The callback that was passed to
2492      *                 {@link #registerForCommunicationAllowedStateChanged(Executor,
2493      *                 SatelliteCommunicationAllowedStateCallback)}
2494      * @throws SecurityException     if the caller doesn't have required permission.
2495      * @throws IllegalStateException if the Telephony process is not currently available.
2496      * @hide
2497      */
2498     @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
2499     @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
unregisterForCommunicationAllowedStateChanged( @onNull SatelliteCommunicationAllowedStateCallback callback)2500     public void unregisterForCommunicationAllowedStateChanged(
2501             @NonNull SatelliteCommunicationAllowedStateCallback callback) {
2502         Objects.requireNonNull(callback);
2503         ISatelliteCommunicationAllowedStateCallback internalCallback =
2504                 sSatelliteCommunicationAllowedStateCallbackMap.remove(callback);
2505 
2506         try {
2507             ITelephony telephony = getITelephony();
2508             if (telephony != null) {
2509                 if (internalCallback != null) {
2510                     telephony.unregisterForCommunicationAllowedStateChanged(mSubId,
2511                             internalCallback);
2512                 } else {
2513                     loge("unregisterForCommunicationAllowedStateChanged: No internal callback.");
2514                 }
2515             } else {
2516                 throw new IllegalStateException("telephony service is null.");
2517             }
2518         } catch (RemoteException ex) {
2519             loge("unregisterForCommunicationAllowedStateChanged() RemoteException: " + ex);
2520             ex.rethrowAsRuntimeException();
2521         }
2522     }
2523 
2524     /**
2525      * Request to get the {@link SatelliteSessionStats} of the satellite service.
2526      *
2527      * @param executor The executor on which the callback will be called.
2528      * @param callback The callback object to which the result will be delivered.
2529      *                 If the request is successful, {@link OutcomeReceiver#onResult(Object)}
2530      *                 will return the {@link SatelliteSessionStats} of the satellite service.
2531      *                 If the request is not successful, {@link OutcomeReceiver#onError(Throwable)}
2532      *                 will return a {@link SatelliteException} with the {@link SatelliteResult}.
2533      *
2534      * @throws SecurityException if the caller doesn't have required permission.
2535      * @hide
2536      */
2537     @RequiresPermission(allOf = {Manifest.permission.PACKAGE_USAGE_STATS,
2538             Manifest.permission.MODIFY_PHONE_STATE})
2539     @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
requestSessionStats(@onNull @allbackExecutor Executor executor, @NonNull OutcomeReceiver<SatelliteSessionStats, SatelliteException> callback)2540     public void requestSessionStats(@NonNull @CallbackExecutor Executor executor,
2541             @NonNull OutcomeReceiver<SatelliteSessionStats, SatelliteException> callback) {
2542         Objects.requireNonNull(executor);
2543         Objects.requireNonNull(callback);
2544 
2545         try {
2546             ITelephony telephony = getITelephony();
2547             if (telephony != null) {
2548                 ResultReceiver receiver = new ResultReceiver(null) {
2549                     @Override
2550                     protected void onReceiveResult(int resultCode, Bundle resultData) {
2551                         if (resultCode == SATELLITE_RESULT_SUCCESS) {
2552                             if (resultData.containsKey(KEY_SESSION_STATS)) {
2553                                 SatelliteSessionStats stats =
2554                                         resultData.getParcelable(KEY_SESSION_STATS,
2555                                                 SatelliteSessionStats.class);
2556                                 executor.execute(() -> Binder.withCleanCallingIdentity(() ->
2557                                         callback.onResult(stats)));
2558                             } else {
2559                                 loge("KEY_SESSION_STATS does not exist.");
2560                                 executor.execute(() -> Binder.withCleanCallingIdentity(() ->
2561                                         callback.onError(new SatelliteException(
2562                                                 SATELLITE_RESULT_REQUEST_FAILED))));
2563                             }
2564                         } else {
2565                             executor.execute(() -> Binder.withCleanCallingIdentity(() ->
2566                                     callback.onError(new SatelliteException(resultCode))));
2567                         }
2568                     }
2569                 };
2570                 telephony.requestSatelliteSessionStats(mSubId, receiver);
2571             } else {
2572                 loge("requestSessionStats() invalid telephony");
2573                 executor.execute(() -> Binder.withCleanCallingIdentity(() -> callback.onError(
2574                         new SatelliteException(SATELLITE_RESULT_ILLEGAL_STATE))));
2575             }
2576         } catch (RemoteException ex) {
2577             loge("requestSessionStats() RemoteException: " + ex);
2578             executor.execute(() -> Binder.withCleanCallingIdentity(() -> callback.onError(
2579                     new SatelliteException(SATELLITE_RESULT_ILLEGAL_STATE))));
2580         }
2581     }
2582 
2583     @Nullable
getITelephony()2584     private static ITelephony getITelephony() {
2585         ITelephony binder = ITelephony.Stub.asInterface(TelephonyFrameworkInitializer
2586                 .getTelephonyServiceManager()
2587                 .getTelephonyServiceRegisterer()
2588                 .get());
2589         return binder;
2590     }
2591 
logd(@onNull String log)2592     private static void logd(@NonNull String log) {
2593         Rlog.d(TAG, log);
2594     }
2595 
loge(@onNull String log)2596     private static void loge(@NonNull String log) {
2597         Rlog.e(TAG, log);
2598     }
2599 }
2600