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.IntDef;
22 import android.annotation.NonNull;
23 import android.annotation.Nullable;
24 import android.annotation.RequiresFeature;
25 import android.annotation.RequiresPermission;
26 import android.content.Context;
27 import android.content.pm.PackageManager;
28 import android.os.Binder;
29 import android.os.Bundle;
30 import android.os.CancellationSignal;
31 import android.os.ICancellationSignal;
32 import android.os.OutcomeReceiver;
33 import android.os.RemoteException;
34 import android.os.ResultReceiver;
35 import android.telephony.SubscriptionManager;
36 import android.telephony.TelephonyFrameworkInitializer;
37 
38 import com.android.internal.telephony.IIntegerConsumer;
39 import com.android.internal.telephony.ITelephony;
40 import com.android.internal.telephony.IVoidConsumer;
41 import com.android.telephony.Rlog;
42 
43 import java.lang.annotation.Retention;
44 import java.lang.annotation.RetentionPolicy;
45 import java.time.Duration;
46 import java.util.Objects;
47 import java.util.concurrent.ConcurrentHashMap;
48 import java.util.concurrent.Executor;
49 import java.util.function.Consumer;
50 
51 /**
52  * Manages satellite operations such as provisioning, pointing, messaging, location sharing, etc.
53  * To get the object, call {@link Context#getSystemService(String)}.
54  *
55  * @hide
56  */
57 @RequiresFeature(PackageManager.FEATURE_TELEPHONY_SATELLITE)
58 public class SatelliteManager {
59     private static final String TAG = "SatelliteManager";
60 
61     private static final ConcurrentHashMap<SatelliteDatagramCallback, ISatelliteDatagramCallback>
62             sSatelliteDatagramCallbackMap = new ConcurrentHashMap<>();
63     private static final ConcurrentHashMap<SatelliteProvisionStateCallback,
64             ISatelliteProvisionStateCallback> sSatelliteProvisionStateCallbackMap =
65             new ConcurrentHashMap<>();
66     private static final ConcurrentHashMap<SatelliteStateCallback, ISatelliteStateCallback>
67             sSatelliteStateCallbackMap = new ConcurrentHashMap<>();
68     private static final ConcurrentHashMap<SatelliteTransmissionUpdateCallback,
69             ISatelliteTransmissionUpdateCallback> sSatelliteTransmissionUpdateCallbackMap =
70             new ConcurrentHashMap<>();
71 
72     private final int mSubId;
73 
74     /**
75      * Context this SatelliteManager is for.
76      */
77     @Nullable private final Context mContext;
78 
79     /**
80      * Create an instance of the SatelliteManager.
81      *
82      * @param context The context the SatelliteManager belongs to.
83      * @hide
84      */
85 
SatelliteManager(@ullable Context context)86     public SatelliteManager(@Nullable Context context) {
87         this(context, SubscriptionManager.DEFAULT_SUBSCRIPTION_ID);
88     }
89 
90     /**
91      * Create an instance of the SatelliteManager associated with a particular subscription.
92      *
93      * @param context The context the SatelliteManager belongs to.
94      * @param subId The subscription ID associated with the SatelliteManager.
95      */
SatelliteManager(@ullable Context context, int subId)96     private SatelliteManager(@Nullable Context context, int subId) {
97         mContext = context;
98         mSubId = subId;
99     }
100 
101     /**
102      * Exception from the satellite service containing the {@link SatelliteError} error code.
103      */
104     public static class SatelliteException extends Exception {
105         @SatelliteError private final int mErrorCode;
106 
107         /**
108          * Create a SatelliteException with a given error code.
109          *
110          * @param errorCode The {@link SatelliteError}.
111          */
SatelliteException(@atelliteError int errorCode)112         public SatelliteException(@SatelliteError int errorCode) {
113             mErrorCode = errorCode;
114         }
115 
116         /**
117          * Get the error code returned from the satellite service.
118          *
119          * @return The {@link SatelliteError}.
120          */
getErrorCode()121         @SatelliteError public int getErrorCode() {
122             return mErrorCode;
123         }
124     }
125 
126     /**
127      * Bundle key to get the response from
128      * {@link #requestIsSatelliteEnabled(Executor, OutcomeReceiver)}.
129      * @hide
130      */
131 
132     public static final String KEY_SATELLITE_ENABLED = "satellite_enabled";
133 
134     /**
135      * Bundle key to get the response from
136      * {@link #requestIsDemoModeEnabled(Executor, OutcomeReceiver)}.
137      * @hide
138      */
139 
140     public static final String KEY_DEMO_MODE_ENABLED = "demo_mode_enabled";
141 
142     /**
143      * Bundle key to get the response from
144      * {@link #requestIsSatelliteSupported(Executor, OutcomeReceiver)}.
145      * @hide
146      */
147 
148     public static final String KEY_SATELLITE_SUPPORTED = "satellite_supported";
149 
150     /**
151      * Bundle key to get the response from
152      * {@link #requestSatelliteCapabilities(Executor, OutcomeReceiver)}.
153      * @hide
154      */
155 
156     public static final String KEY_SATELLITE_CAPABILITIES = "satellite_capabilities";
157 
158     /**
159      * Bundle key to get the response from
160      * {@link #requestIsSatelliteProvisioned(Executor, OutcomeReceiver)}.
161      * @hide
162      */
163 
164     public static final String KEY_SATELLITE_PROVISIONED = "satellite_provisioned";
165 
166     /**
167      * Bundle key to get the response from
168      * {@link #requestIsSatelliteCommunicationAllowedForCurrentLocation(Executor, OutcomeReceiver)}.
169      * @hide
170      */
171 
172     public static final String KEY_SATELLITE_COMMUNICATION_ALLOWED =
173             "satellite_communication_allowed";
174 
175     /**
176      * Bundle key to get the response from
177      * {@link #requestTimeForNextSatelliteVisibility(Executor, OutcomeReceiver)}.
178      * @hide
179      */
180 
181     public static final String KEY_SATELLITE_NEXT_VISIBILITY = "satellite_next_visibility";
182 
183     /**
184      * The request was successfully processed.
185      */
186     public static final int SATELLITE_ERROR_NONE = 0;
187     /**
188      * A generic error which should be used only when other specific errors cannot be used.
189      */
190     public static final int SATELLITE_ERROR = 1;
191     /**
192      * Error received from the satellite server.
193      */
194     public static final int SATELLITE_SERVER_ERROR = 2;
195     /**
196      * Error received from the vendor service. This generic error code should be used
197      * only when the error cannot be mapped to other specific service error codes.
198      */
199     public static final int SATELLITE_SERVICE_ERROR = 3;
200     /**
201      * Error received from satellite modem. This generic error code should be used only when
202      * the error cannot be mapped to other specific modem error codes.
203      */
204     public static final int SATELLITE_MODEM_ERROR = 4;
205     /**
206      * Error received from the satellite network. This generic error code should be used only when
207      * the error cannot be mapped to other specific network error codes.
208      */
209     public static final int SATELLITE_NETWORK_ERROR = 5;
210     /**
211      * Telephony is not in a valid state to receive requests from clients.
212      */
213     public static final int SATELLITE_INVALID_TELEPHONY_STATE = 6;
214     /**
215      * Satellite modem is not in a valid state to receive requests from clients.
216      */
217     public static final int SATELLITE_INVALID_MODEM_STATE = 7;
218     /**
219      * Either vendor service, or modem, or Telephony framework has received a request with
220      * invalid arguments from its clients.
221      */
222     public static final int SATELLITE_INVALID_ARGUMENTS = 8;
223     /**
224      * Telephony framework failed to send a request or receive a response from the vendor service
225      * or satellite modem due to internal error.
226      */
227     public static final int SATELLITE_REQUEST_FAILED = 9;
228     /**
229      * Radio did not start or is resetting.
230      */
231     public static final int SATELLITE_RADIO_NOT_AVAILABLE = 10;
232     /**
233      * The request is not supported by either the satellite modem or the network.
234      */
235     public static final int SATELLITE_REQUEST_NOT_SUPPORTED = 11;
236     /**
237      * Satellite modem or network has no resources available to handle requests from clients.
238      */
239     public static final int SATELLITE_NO_RESOURCES = 12;
240     /**
241      * Satellite service is not provisioned yet.
242      */
243     public static final int SATELLITE_SERVICE_NOT_PROVISIONED = 13;
244     /**
245      * Satellite service provision is already in progress.
246      */
247     public static final int SATELLITE_SERVICE_PROVISION_IN_PROGRESS = 14;
248     /**
249      * The ongoing request was aborted by either the satellite modem or the network.
250      * This error is also returned when framework decides to abort current send request as one
251      * of the previous send request failed.
252      */
253     public static final int SATELLITE_REQUEST_ABORTED = 15;
254     /**
255      * The device/subscriber is barred from accessing the satellite service.
256      */
257     public static final int SATELLITE_ACCESS_BARRED = 16;
258     /**
259      * Satellite modem timeout to receive ACK or response from the satellite network after
260      * sending a request to the network.
261      */
262     public static final int SATELLITE_NETWORK_TIMEOUT = 17;
263     /**
264      * Satellite network is not reachable from the modem.
265      */
266     public static final int SATELLITE_NOT_REACHABLE = 18;
267     /**
268      * The device/subscriber is not authorized to register with the satellite service provider.
269      */
270     public static final int SATELLITE_NOT_AUTHORIZED = 19;
271     /**
272      * The device does not support satellite.
273      */
274     public static final int SATELLITE_NOT_SUPPORTED = 20;
275 
276     /**
277      * The current request is already in-progress.
278      */
279     public static final int SATELLITE_REQUEST_IN_PROGRESS = 21;
280 
281     /**
282      * Satellite modem is currently busy due to which current request cannot be processed.
283      */
284     public static final int SATELLITE_MODEM_BUSY = 22;
285 
286     /** @hide */
287     @IntDef(prefix = {"SATELLITE_"}, value = {
288             SATELLITE_ERROR_NONE,
289             SATELLITE_ERROR,
290             SATELLITE_SERVER_ERROR,
291             SATELLITE_SERVICE_ERROR,
292             SATELLITE_MODEM_ERROR,
293             SATELLITE_NETWORK_ERROR,
294             SATELLITE_INVALID_TELEPHONY_STATE,
295             SATELLITE_INVALID_MODEM_STATE,
296             SATELLITE_INVALID_ARGUMENTS,
297             SATELLITE_REQUEST_FAILED,
298             SATELLITE_RADIO_NOT_AVAILABLE,
299             SATELLITE_REQUEST_NOT_SUPPORTED,
300             SATELLITE_NO_RESOURCES,
301             SATELLITE_SERVICE_NOT_PROVISIONED,
302             SATELLITE_SERVICE_PROVISION_IN_PROGRESS,
303             SATELLITE_REQUEST_ABORTED,
304             SATELLITE_ACCESS_BARRED,
305             SATELLITE_NETWORK_TIMEOUT,
306             SATELLITE_NOT_REACHABLE,
307             SATELLITE_NOT_AUTHORIZED,
308             SATELLITE_NOT_SUPPORTED,
309             SATELLITE_REQUEST_IN_PROGRESS,
310             SATELLITE_MODEM_BUSY
311     })
312     @Retention(RetentionPolicy.SOURCE)
313     public @interface SatelliteError {}
314 
315     /**
316      * Unknown Non-Terrestrial radio technology. This generic radio technology should be used
317      * only when the radio technology cannot be mapped to other specific radio technologies.
318      */
319     public static final int NT_RADIO_TECHNOLOGY_UNKNOWN = 0;
320     /**
321      * 3GPP NB-IoT (Narrowband Internet of Things) over Non-Terrestrial-Networks technology.
322      */
323     public static final int NT_RADIO_TECHNOLOGY_NB_IOT_NTN = 1;
324     /**
325      * 3GPP 5G NR over Non-Terrestrial-Networks technology.
326      */
327     public static final int NT_RADIO_TECHNOLOGY_NR_NTN = 2;
328     /**
329      * 3GPP eMTC (enhanced Machine-Type Communication) over Non-Terrestrial-Networks technology.
330      */
331     public static final int NT_RADIO_TECHNOLOGY_EMTC_NTN = 3;
332     /**
333      * Proprietary technology.
334      */
335     public static final int NT_RADIO_TECHNOLOGY_PROPRIETARY = 4;
336 
337     /** @hide */
338     @IntDef(prefix = "NT_RADIO_TECHNOLOGY_", value = {
339             NT_RADIO_TECHNOLOGY_UNKNOWN,
340             NT_RADIO_TECHNOLOGY_NB_IOT_NTN,
341             NT_RADIO_TECHNOLOGY_NR_NTN,
342             NT_RADIO_TECHNOLOGY_EMTC_NTN,
343             NT_RADIO_TECHNOLOGY_PROPRIETARY
344     })
345     @Retention(RetentionPolicy.SOURCE)
346     public @interface NTRadioTechnology {}
347 
348     /** Suggested device hold position is unknown. */
349     public static final int DEVICE_HOLD_POSITION_UNKNOWN = 0;
350     /** User is suggested to hold the device in portrait mode. */
351     public static final int DEVICE_HOLD_POSITION_PORTRAIT = 1;
352     /** User is suggested to hold the device in landscape mode with left hand. */
353     public static final int DEVICE_HOLD_POSITION_LANDSCAPE_LEFT = 2;
354     /** User is suggested to hold the device in landscape mode with right hand. */
355     public static final int DEVICE_HOLD_POSITION_LANDSCAPE_RIGHT = 3;
356 
357     /** @hide */
358     @IntDef(prefix = {"DEVICE_HOLD_POSITION_"}, value = {
359             DEVICE_HOLD_POSITION_UNKNOWN,
360             DEVICE_HOLD_POSITION_PORTRAIT,
361             DEVICE_HOLD_POSITION_LANDSCAPE_LEFT,
362             DEVICE_HOLD_POSITION_LANDSCAPE_RIGHT
363        })
364     @Retention(RetentionPolicy.SOURCE)
365     public @interface DeviceHoldPosition {}
366 
367     /** Display mode is unknown. */
368     public static final int DISPLAY_MODE_UNKNOWN = 0;
369     /** Display mode of the device used for satellite communication for non-foldable phones. */
370     public static final int DISPLAY_MODE_FIXED = 1;
371     /** Display mode of the device used for satellite communication for foldabale phones when the
372      * device is opened. */
373     public static final int DISPLAY_MODE_OPENED = 2;
374     /** Display mode of the device used for satellite communication for foldabable phones when the
375      * device is closed. */
376     public static final int DISPLAY_MODE_CLOSED = 3;
377 
378     /** @hide */
379     @IntDef(prefix = {"ANTENNA_POSITION_"}, value = {
380             DISPLAY_MODE_UNKNOWN,
381             DISPLAY_MODE_FIXED,
382             DISPLAY_MODE_OPENED,
383             DISPLAY_MODE_CLOSED
384     })
385     @Retention(RetentionPolicy.SOURCE)
386     public @interface DisplayMode {}
387 
388     /**
389      * Request to enable or disable the satellite modem and demo mode. If the satellite modem is
390      * enabled, this may also disable the cellular modem, and if the satellite modem is disabled,
391      * this may also re-enable the cellular modem.
392      *
393      * @param enableSatellite {@code true} to enable the satellite modem and
394      *                        {@code false} to disable.
395      * @param enableDemoMode {@code true} to enable demo mode and {@code false} to disable.
396      * @param executor The executor on which the error code listener will be called.
397      * @param resultListener Listener for the {@link SatelliteError} result of the operation.
398      *
399      * @throws SecurityException if the caller doesn't have required permission.
400      * @throws IllegalStateException if the Telephony process is not currently available.
401      */
402     @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
403 
requestSatelliteEnabled(boolean enableSatellite, boolean enableDemoMode, @NonNull @CallbackExecutor Executor executor, @SatelliteError @NonNull Consumer<Integer> resultListener)404     public void requestSatelliteEnabled(boolean enableSatellite, boolean enableDemoMode,
405             @NonNull @CallbackExecutor Executor executor,
406             @SatelliteError @NonNull Consumer<Integer> resultListener) {
407         Objects.requireNonNull(executor);
408         Objects.requireNonNull(resultListener);
409 
410         try {
411             ITelephony telephony = getITelephony();
412             if (telephony != null) {
413                 IIntegerConsumer errorCallback = new IIntegerConsumer.Stub() {
414                     @Override
415                     public void accept(int result) {
416                         executor.execute(() -> Binder.withCleanCallingIdentity(
417                                 () -> resultListener.accept(result)));
418                     }
419                 };
420                 telephony.requestSatelliteEnabled(mSubId, enableSatellite, enableDemoMode,
421                         errorCallback);
422             } else {
423                 throw new IllegalStateException("telephony service is null.");
424             }
425         } catch (RemoteException ex) {
426             Rlog.e(TAG, "requestSatelliteEnabled() RemoteException: ", ex);
427             ex.rethrowFromSystemServer();
428         }
429     }
430 
431     /**
432      * Request to get whether the satellite modem is enabled.
433      *
434      * @param executor The executor on which the callback will be called.
435      * @param callback The callback object to which the result will be delivered.
436      *                 If the request is successful, {@link OutcomeReceiver#onResult(Object)}
437      *                 will return a {@code boolean} with value {@code true} if the satellite modem
438      *                 is enabled and {@code false} otherwise.
439      *                 If the request is not successful, {@link OutcomeReceiver#onError(Throwable)}
440      *                 will return a {@link SatelliteException} with the {@link SatelliteError}.
441      *
442      * @throws SecurityException if the caller doesn't have required permission.
443      * @throws IllegalStateException if the Telephony process is not currently available.
444      */
445     @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
446 
requestIsSatelliteEnabled(@onNull @allbackExecutor Executor executor, @NonNull OutcomeReceiver<Boolean, SatelliteException> callback)447     public void requestIsSatelliteEnabled(@NonNull @CallbackExecutor Executor executor,
448             @NonNull OutcomeReceiver<Boolean, SatelliteException> callback) {
449         Objects.requireNonNull(executor);
450         Objects.requireNonNull(callback);
451 
452         try {
453             ITelephony telephony = getITelephony();
454             if (telephony != null) {
455                 ResultReceiver receiver = new ResultReceiver(null) {
456                     @Override
457                     protected void onReceiveResult(int resultCode, Bundle resultData) {
458                         if (resultCode == SATELLITE_ERROR_NONE) {
459                             if (resultData.containsKey(KEY_SATELLITE_ENABLED)) {
460                                 boolean isSatelliteEnabled =
461                                         resultData.getBoolean(KEY_SATELLITE_ENABLED);
462                                 executor.execute(() -> Binder.withCleanCallingIdentity(() ->
463                                         callback.onResult(isSatelliteEnabled)));
464                             } else {
465                                 loge("KEY_SATELLITE_ENABLED does not exist.");
466                                 executor.execute(() -> Binder.withCleanCallingIdentity(() ->
467                                         callback.onError(
468                                                 new SatelliteException(SATELLITE_REQUEST_FAILED))));
469                             }
470                         } else {
471                             executor.execute(() -> Binder.withCleanCallingIdentity(() ->
472                                     callback.onError(new SatelliteException(resultCode))));
473                         }
474                     }
475                 };
476                 telephony.requestIsSatelliteEnabled(mSubId, receiver);
477             } else {
478                 throw new IllegalStateException("telephony service is null.");
479             }
480         } catch (RemoteException ex) {
481             loge("requestIsSatelliteEnabled() RemoteException: " + ex);
482             ex.rethrowFromSystemServer();
483         }
484     }
485 
486     /**
487      * Request to get whether the satellite service demo mode is enabled.
488      *
489      * @param executor The executor on which the callback will be called.
490      * @param callback The callback object to which the result will be delivered.
491      *                 If the request is successful, {@link OutcomeReceiver#onResult(Object)}
492      *                 will return a {@code boolean} with value {@code true} if demo mode is enabled
493      *                 and {@code false} otherwise.
494      *                 If the request is not successful, {@link OutcomeReceiver#onError(Throwable)}
495      *                 will return a {@link SatelliteException} with the {@link SatelliteError}.
496      *
497      * @throws SecurityException if the caller doesn't have required permission.
498      * @throws IllegalStateException if the Telephony process is not currently available.
499      */
500     @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
501 
requestIsDemoModeEnabled(@onNull @allbackExecutor Executor executor, @NonNull OutcomeReceiver<Boolean, SatelliteException> callback)502     public void requestIsDemoModeEnabled(@NonNull @CallbackExecutor Executor executor,
503             @NonNull OutcomeReceiver<Boolean, SatelliteException> callback) {
504         Objects.requireNonNull(executor);
505         Objects.requireNonNull(callback);
506 
507         try {
508             ITelephony telephony = getITelephony();
509             if (telephony != null) {
510                 ResultReceiver receiver = new ResultReceiver(null) {
511                     @Override
512                     protected void onReceiveResult(int resultCode, Bundle resultData) {
513                         if (resultCode == SATELLITE_ERROR_NONE) {
514                             if (resultData.containsKey(KEY_DEMO_MODE_ENABLED)) {
515                                 boolean isDemoModeEnabled =
516                                         resultData.getBoolean(KEY_DEMO_MODE_ENABLED);
517                                 executor.execute(() -> Binder.withCleanCallingIdentity(() ->
518                                         callback.onResult(isDemoModeEnabled)));
519                             } else {
520                                 loge("KEY_DEMO_MODE_ENABLED does not exist.");
521                                 executor.execute(() -> Binder.withCleanCallingIdentity(() ->
522                                         callback.onError(
523                                                 new SatelliteException(SATELLITE_REQUEST_FAILED))));
524                             }
525                         } else {
526                             executor.execute(() -> Binder.withCleanCallingIdentity(() ->
527                                     callback.onError(new SatelliteException(resultCode))));
528                         }
529                     }
530                 };
531                 telephony.requestIsDemoModeEnabled(mSubId, receiver);
532             } else {
533                 throw new IllegalStateException("telephony service is null.");
534             }
535         } catch (RemoteException ex) {
536             loge("requestIsDemoModeEnabled() RemoteException: " + ex);
537             ex.rethrowFromSystemServer();
538         }
539     }
540 
541     /**
542      * Request to get whether the satellite service is supported on the device.
543      *
544      * @param executor The executor on which the callback will be called.
545      * @param callback The callback object to which the result will be delivered.
546      *                 If the request is successful, {@link OutcomeReceiver#onResult(Object)}
547      *                 will return a {@code boolean} with value {@code true} if the satellite
548      *                 service is supported on the device and {@code false} otherwise.
549      *                 If the request is not successful, {@link OutcomeReceiver#onError(Throwable)}
550      *                 will return a {@link SatelliteException} with the {@link SatelliteError}.
551      *
552      * @throws IllegalStateException if the Telephony process is not currently available.
553      */
554 
requestIsSatelliteSupported(@onNull @allbackExecutor Executor executor, @NonNull OutcomeReceiver<Boolean, SatelliteException> callback)555     public void requestIsSatelliteSupported(@NonNull @CallbackExecutor Executor executor,
556             @NonNull OutcomeReceiver<Boolean, SatelliteException> callback) {
557         Objects.requireNonNull(executor);
558         Objects.requireNonNull(callback);
559 
560         try {
561             ITelephony telephony = getITelephony();
562             if (telephony != null) {
563                 ResultReceiver receiver = new ResultReceiver(null) {
564                     @Override
565                     protected void onReceiveResult(int resultCode, Bundle resultData) {
566                         if (resultCode == SATELLITE_ERROR_NONE) {
567                             if (resultData.containsKey(KEY_SATELLITE_SUPPORTED)) {
568                                 boolean isSatelliteSupported =
569                                         resultData.getBoolean(KEY_SATELLITE_SUPPORTED);
570                                 executor.execute(() -> Binder.withCleanCallingIdentity(() ->
571                                         callback.onResult(isSatelliteSupported)));
572                             } else {
573                                 loge("KEY_SATELLITE_SUPPORTED does not exist.");
574                                 executor.execute(() -> Binder.withCleanCallingIdentity(() ->
575                                         callback.onError(
576                                                 new SatelliteException(SATELLITE_REQUEST_FAILED))));
577                             }
578                         } else {
579                             executor.execute(() -> Binder.withCleanCallingIdentity(() ->
580                                     callback.onError(new SatelliteException(resultCode))));
581                         }
582                     }
583                 };
584                 telephony.requestIsSatelliteSupported(mSubId, receiver);
585             } else {
586                 throw new IllegalStateException("telephony service is null.");
587             }
588         } catch (RemoteException ex) {
589             loge("requestIsSatelliteSupported() RemoteException: " + ex);
590             ex.rethrowFromSystemServer();
591         }
592     }
593 
594     /**
595      * Request to get the {@link SatelliteCapabilities} of the satellite service.
596      *
597      * @param executor The executor on which the callback will be called.
598      * @param callback The callback object to which the result will be delivered.
599      *                 If the request is successful, {@link OutcomeReceiver#onResult(Object)}
600      *                 will return the {@link SatelliteCapabilities} of the satellite service.
601      *                 If the request is not successful, {@link OutcomeReceiver#onError(Throwable)}
602      *                 will return a {@link SatelliteException} with the {@link SatelliteError}.
603      *
604      * @throws SecurityException if the caller doesn't have required permission.
605      * @throws IllegalStateException if the Telephony process is not currently available.
606      */
607     @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
608 
requestSatelliteCapabilities(@onNull @allbackExecutor Executor executor, @NonNull OutcomeReceiver<SatelliteCapabilities, SatelliteException> callback)609     public void requestSatelliteCapabilities(@NonNull @CallbackExecutor Executor executor,
610             @NonNull OutcomeReceiver<SatelliteCapabilities, SatelliteException> callback) {
611         Objects.requireNonNull(executor);
612         Objects.requireNonNull(callback);
613 
614         try {
615             ITelephony telephony = getITelephony();
616             if (telephony != null) {
617                 ResultReceiver receiver = new ResultReceiver(null) {
618                     @Override
619                     protected void onReceiveResult(int resultCode, Bundle resultData) {
620                         if (resultCode == SATELLITE_ERROR_NONE) {
621                             if (resultData.containsKey(KEY_SATELLITE_CAPABILITIES)) {
622                                 SatelliteCapabilities capabilities =
623                                         resultData.getParcelable(KEY_SATELLITE_CAPABILITIES,
624                                                 SatelliteCapabilities.class);
625                                 executor.execute(() -> Binder.withCleanCallingIdentity(() ->
626                                         callback.onResult(capabilities)));
627                             } else {
628                                 loge("KEY_SATELLITE_CAPABILITIES does not exist.");
629                                 executor.execute(() -> Binder.withCleanCallingIdentity(() ->
630                                         callback.onError(
631                                                 new SatelliteException(SATELLITE_REQUEST_FAILED))));
632                             }
633                         } else {
634                             executor.execute(() -> Binder.withCleanCallingIdentity(() ->
635                                     callback.onError(new SatelliteException(resultCode))));
636                         }
637                     }
638                 };
639                 telephony.requestSatelliteCapabilities(mSubId, receiver);
640             } else {
641                 throw new IllegalStateException("telephony service is null.");
642             }
643         } catch (RemoteException ex) {
644             loge("requestSatelliteCapabilities() RemoteException: " + ex);
645             ex.rethrowFromSystemServer();
646         }
647     }
648 
649     /**
650      * The default state indicating that datagram transfer is idle.
651      * This should be sent if there are no message transfer activity happening.
652      */
653     public static final int SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE = 0;
654     /**
655      * A transition state indicating that a datagram is being sent.
656      */
657     public static final int SATELLITE_DATAGRAM_TRANSFER_STATE_SENDING = 1;
658     /**
659      * An end state indicating that datagram sending completed successfully.
660      * After datagram transfer completes, {@link #SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE}
661      * will be sent if no more messages are pending.
662      */
663     public static final int SATELLITE_DATAGRAM_TRANSFER_STATE_SEND_SUCCESS = 2;
664     /**
665      * An end state indicating that datagram sending completed with a failure.
666      * After datagram transfer completes, {@link #SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE}
667      * must be sent before reporting any additional datagram transfer state changes. All pending
668      * messages will be reported as failed, to the corresponding applications.
669      */
670     public static final int SATELLITE_DATAGRAM_TRANSFER_STATE_SEND_FAILED = 3;
671     /**
672      * A transition state indicating that a datagram is being received.
673      */
674     public static final int SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVING = 4;
675     /**
676      * An end state indicating that datagram receiving completed successfully.
677      * After datagram transfer completes, {@link #SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE}
678      * will be sent if no more messages are pending.
679      */
680     public static final int SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVE_SUCCESS = 5;
681     /**
682      * An end state indicating that datagram receive operation found that there are no
683      * messages to be retrieved from the satellite.
684      * After datagram transfer completes, {@link #SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE}
685      * will be sent if no more messages are pending.
686      */
687     public static final int SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVE_NONE = 6;
688     /**
689      * An end state indicating that datagram receive completed with a failure.
690      * After datagram transfer completes, {@link #SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE}
691      * will be sent if no more messages are pending.
692      */
693     public static final int SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVE_FAILED = 7;
694     /**
695      * The datagram transfer state is unknown. This generic datagram transfer state should be used
696      * only when the datagram transfer state cannot be mapped to other specific datagram transfer
697      * states.
698      */
699     public static final int SATELLITE_DATAGRAM_TRANSFER_STATE_UNKNOWN = -1;
700 
701     /** @hide */
702     @IntDef(prefix = {"SATELLITE_DATAGRAM_TRANSFER_STATE_"}, value = {
703             SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE,
704             SATELLITE_DATAGRAM_TRANSFER_STATE_SENDING,
705             SATELLITE_DATAGRAM_TRANSFER_STATE_SEND_SUCCESS,
706             SATELLITE_DATAGRAM_TRANSFER_STATE_SEND_FAILED,
707             SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVING,
708             SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVE_SUCCESS,
709             SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVE_NONE,
710             SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVE_FAILED,
711             SATELLITE_DATAGRAM_TRANSFER_STATE_UNKNOWN
712     })
713     @Retention(RetentionPolicy.SOURCE)
714     public @interface SatelliteDatagramTransferState {}
715     // TODO: Split into two enums for sending and receiving states
716 
717     /**
718      * Satellite modem is in idle state.
719      */
720     public static final int SATELLITE_MODEM_STATE_IDLE = 0;
721     /**
722      * Satellite modem is listening for incoming datagrams.
723      */
724     public static final int SATELLITE_MODEM_STATE_LISTENING = 1;
725     /**
726      * Satellite modem is sending and/or receiving datagrams.
727      */
728     public static final int SATELLITE_MODEM_STATE_DATAGRAM_TRANSFERRING = 2;
729     /**
730      * Satellite modem is retrying to send and/or receive datagrams.
731      */
732     public static final int SATELLITE_MODEM_STATE_DATAGRAM_RETRYING = 3;
733     /**
734      * Satellite modem is powered off.
735      */
736     public static final int SATELLITE_MODEM_STATE_OFF = 4;
737     /**
738      * Satellite modem is unavailable.
739      */
740     public static final int SATELLITE_MODEM_STATE_UNAVAILABLE = 5;
741     /**
742      * Satellite modem state is unknown. This generic modem state should be used only when the
743      * modem state cannot be mapped to other specific modem states.
744      */
745     public static final int SATELLITE_MODEM_STATE_UNKNOWN = -1;
746 
747     /** @hide */
748     @IntDef(prefix = {"SATELLITE_MODEM_STATE_"}, value = {
749             SATELLITE_MODEM_STATE_IDLE,
750             SATELLITE_MODEM_STATE_LISTENING,
751             SATELLITE_MODEM_STATE_DATAGRAM_TRANSFERRING,
752             SATELLITE_MODEM_STATE_DATAGRAM_RETRYING,
753             SATELLITE_MODEM_STATE_OFF,
754             SATELLITE_MODEM_STATE_UNAVAILABLE,
755             SATELLITE_MODEM_STATE_UNKNOWN
756     })
757     @Retention(RetentionPolicy.SOURCE)
758     public @interface SatelliteModemState {}
759 
760     /**
761      * Datagram type is unknown. This generic datagram type should be used only when the
762      * datagram type cannot be mapped to other specific datagram types.
763      */
764     public static final int DATAGRAM_TYPE_UNKNOWN = 0;
765     /**
766      * Datagram type indicating that the datagram to be sent or received is of type SOS message.
767      */
768     public static final int DATAGRAM_TYPE_SOS_MESSAGE = 1;
769     /**
770      * Datagram type indicating that the datagram to be sent or received is of type
771      * location sharing.
772      */
773     public static final int DATAGRAM_TYPE_LOCATION_SHARING = 2;
774 
775     /** @hide */
776     @IntDef(prefix = "DATAGRAM_TYPE_", value = {
777             DATAGRAM_TYPE_UNKNOWN,
778             DATAGRAM_TYPE_SOS_MESSAGE,
779             DATAGRAM_TYPE_LOCATION_SHARING
780     })
781     @Retention(RetentionPolicy.SOURCE)
782     public @interface DatagramType {}
783 
784     /**
785      * Start receiving satellite transmission updates.
786      * This can be called by the pointing UI when the user starts pointing to the satellite.
787      * Modem should continue to report the pointing input as the device or satellite moves.
788      * Satellite transmission updates are started only on {@link #SATELLITE_ERROR_NONE}.
789      * All other results indicate that this operation failed.
790      * Once satellite transmission updates begin, position and datagram transfer state updates
791      * will be sent through {@link SatelliteTransmissionUpdateCallback}.
792      *
793      * @param executor The executor on which the callback and error code listener will be called.
794      * @param resultListener Listener for the {@link SatelliteError} result of the operation.
795      * @param callback The callback to notify of satellite transmission updates.
796      *
797      * @throws SecurityException if the caller doesn't have required permission.
798      * @throws IllegalStateException if the Telephony process is not currently available.
799      */
800     @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
801 
startSatelliteTransmissionUpdates(@onNull @allbackExecutor Executor executor, @SatelliteError @NonNull Consumer<Integer> resultListener, @NonNull SatelliteTransmissionUpdateCallback callback)802     public void startSatelliteTransmissionUpdates(@NonNull @CallbackExecutor Executor executor,
803             @SatelliteError @NonNull Consumer<Integer> resultListener,
804             @NonNull SatelliteTransmissionUpdateCallback callback) {
805         Objects.requireNonNull(executor);
806         Objects.requireNonNull(resultListener);
807         Objects.requireNonNull(callback);
808 
809         try {
810             ITelephony telephony = getITelephony();
811             if (telephony != null) {
812                 IIntegerConsumer errorCallback = new IIntegerConsumer.Stub() {
813                     @Override
814                     public void accept(int result) {
815                         executor.execute(() -> Binder.withCleanCallingIdentity(
816                                 () -> resultListener.accept(result)));
817                     }
818                 };
819                 ISatelliteTransmissionUpdateCallback internalCallback =
820                         new ISatelliteTransmissionUpdateCallback.Stub() {
821 
822                             @Override
823                             public void onSatellitePositionChanged(PointingInfo pointingInfo) {
824                                 executor.execute(() -> Binder.withCleanCallingIdentity(
825                                         () -> callback.onSatellitePositionChanged(pointingInfo)));
826                             }
827 
828                             @Override
829                             public void onSendDatagramStateChanged(int state, int sendPendingCount,
830                                     int errorCode) {
831                                 executor.execute(() -> Binder.withCleanCallingIdentity(
832                                         () -> callback.onSendDatagramStateChanged(
833                                                 state, sendPendingCount, errorCode)));
834                             }
835 
836                             @Override
837                             public void onReceiveDatagramStateChanged(int state,
838                                     int receivePendingCount, int errorCode) {
839                                 executor.execute(() -> Binder.withCleanCallingIdentity(
840                                         () -> callback.onReceiveDatagramStateChanged(
841                                                 state, receivePendingCount, errorCode)));
842                             }
843                         };
844                 sSatelliteTransmissionUpdateCallbackMap.put(callback, internalCallback);
845                 telephony.startSatelliteTransmissionUpdates(mSubId, errorCallback,
846                         internalCallback);
847             } else {
848                 throw new IllegalStateException("telephony service is null.");
849             }
850         } catch (RemoteException ex) {
851             loge("startSatelliteTransmissionUpdates() RemoteException: " + ex);
852             ex.rethrowFromSystemServer();
853         }
854     }
855 
856     /**
857      * Stop receiving satellite transmission updates.
858      * This can be called by the pointing UI when the user stops pointing to the satellite.
859      * Satellite transmission updates are stopped and the callback is unregistered only on
860      * {@link #SATELLITE_ERROR_NONE}. All other results that this operation failed.
861      *
862      * @param callback The callback that was passed to {@link
863      * #startSatelliteTransmissionUpdates(Executor, Consumer, SatelliteTransmissionUpdateCallback)}.
864      * @param executor The executor on which the error code listener will be called.
865      * @param resultListener Listener for the {@link SatelliteError} result of the operation.
866      *
867      * @throws SecurityException if the caller doesn't have required permission.
868      * @throws IllegalStateException if the Telephony process is not currently available.
869      */
870     @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
871 
stopSatelliteTransmissionUpdates( @onNull SatelliteTransmissionUpdateCallback callback, @NonNull @CallbackExecutor Executor executor, @SatelliteError @NonNull Consumer<Integer> resultListener)872     public void stopSatelliteTransmissionUpdates(
873             @NonNull SatelliteTransmissionUpdateCallback callback,
874             @NonNull @CallbackExecutor Executor executor,
875             @SatelliteError @NonNull Consumer<Integer> resultListener) {
876         Objects.requireNonNull(callback);
877         Objects.requireNonNull(executor);
878         Objects.requireNonNull(resultListener);
879         ISatelliteTransmissionUpdateCallback internalCallback =
880                 sSatelliteTransmissionUpdateCallbackMap.remove(callback);
881 
882         try {
883             ITelephony telephony = getITelephony();
884             if (telephony != null) {
885                 if (internalCallback != null) {
886                     IIntegerConsumer errorCallback = new IIntegerConsumer.Stub() {
887                         @Override
888                         public void accept(int result) {
889                             executor.execute(() -> Binder.withCleanCallingIdentity(
890                                     () -> resultListener.accept(result)));
891                         }
892                     };
893                     telephony.stopSatelliteTransmissionUpdates(mSubId, errorCallback,
894                             internalCallback);
895                     // TODO: Notify SmsHandler that pointing UI stopped
896                 } else {
897                     loge("stopSatelliteTransmissionUpdates: No internal callback.");
898                     executor.execute(() -> Binder.withCleanCallingIdentity(
899                             () -> resultListener.accept(SATELLITE_INVALID_ARGUMENTS)));
900                 }
901             } else {
902                 throw new IllegalStateException("telephony service is null.");
903             }
904         } catch (RemoteException ex) {
905             loge("stopSatelliteTransmissionUpdates() RemoteException: " + ex);
906             ex.rethrowFromSystemServer();
907         }
908     }
909 
910     /**
911      * Provision the device with a satellite provider.
912      * This is needed if the provider allows dynamic registration.
913      *
914      * @param token The token to be used as a unique identifier for provisioning with satellite
915      *              gateway.
916      * @param provisionData Data from the provisioning app that can be used by provisioning server
917      * @param cancellationSignal The optional signal used by the caller to cancel the provision
918      *                           request. Even when the cancellation is signaled, Telephony will
919      *                           still trigger the callback to return the result of this request.
920      * @param executor The executor on which the error code listener will be called.
921      * @param resultListener Listener for the {@link SatelliteError} result of the operation.
922      *
923      * @throws SecurityException if the caller doesn't have required permission.
924      * @throws IllegalStateException if the Telephony process is not currently available.
925      */
926     @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
927 
provisionSatelliteService(@onNull String token, @NonNull byte[] provisionData, @Nullable CancellationSignal cancellationSignal, @NonNull @CallbackExecutor Executor executor, @SatelliteError @NonNull Consumer<Integer> resultListener)928     public void provisionSatelliteService(@NonNull String token, @NonNull byte[] provisionData,
929             @Nullable CancellationSignal cancellationSignal,
930             @NonNull @CallbackExecutor Executor executor,
931             @SatelliteError @NonNull Consumer<Integer> resultListener) {
932         Objects.requireNonNull(token);
933         Objects.requireNonNull(executor);
934         Objects.requireNonNull(resultListener);
935         Objects.requireNonNull(provisionData);
936 
937         ICancellationSignal cancelRemote = null;
938         try {
939             ITelephony telephony = getITelephony();
940             if (telephony != null) {
941                 IIntegerConsumer errorCallback = new IIntegerConsumer.Stub() {
942                     @Override
943                     public void accept(int result) {
944                         executor.execute(() -> Binder.withCleanCallingIdentity(
945                                 () -> resultListener.accept(result)));
946                     }
947                 };
948                 cancelRemote = telephony.provisionSatelliteService(mSubId, token, provisionData,
949                         errorCallback);
950             } else {
951                 throw new IllegalStateException("telephony service is null.");
952             }
953         } catch (RemoteException ex) {
954             loge("provisionSatelliteService() RemoteException=" + ex);
955             ex.rethrowFromSystemServer();
956         }
957         if (cancellationSignal != null) {
958             cancellationSignal.setRemote(cancelRemote);
959         }
960     }
961 
962     /**
963      * Deprovision the device with the satellite provider.
964      * This is needed if the provider allows dynamic registration. Once deprovisioned,
965      * {@link SatelliteProvisionStateCallback#onSatelliteProvisionStateChanged(boolean)}
966      * should report as deprovisioned.
967      * For provisioning satellite service, refer to
968      * {@link #provisionSatelliteService(String, String, CancellationSignal, Executor, Consumer)}
969      *
970      * @param token The token of the device/subscription to be deprovisioned.
971      * @param resultListener Listener for the {@link SatelliteError} result of the operation.
972      *
973      * @throws SecurityException if the caller doesn't have required permission.
974      * @throws IllegalStateException if the Telephony process is not currently available.
975      */
976     @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
977 
deprovisionSatelliteService(@onNull String token, @NonNull @CallbackExecutor Executor executor, @SatelliteError @NonNull Consumer<Integer> resultListener)978     public void deprovisionSatelliteService(@NonNull String token,
979             @NonNull @CallbackExecutor Executor executor,
980             @SatelliteError @NonNull Consumer<Integer> resultListener) {
981         Objects.requireNonNull(token);
982         Objects.requireNonNull(executor);
983         Objects.requireNonNull(resultListener);
984 
985         try {
986             ITelephony telephony = getITelephony();
987             if (telephony != null) {
988                 IIntegerConsumer errorCallback = new IIntegerConsumer.Stub() {
989                     @Override
990                     public void accept(int result) {
991                         executor.execute(() -> Binder.withCleanCallingIdentity(
992                                 () -> resultListener.accept(result)));
993                     }
994                 };
995                 telephony.deprovisionSatelliteService(mSubId, token, errorCallback);
996             } else {
997                 throw new IllegalStateException("telephony service is null.");
998             }
999         } catch (RemoteException ex) {
1000             loge("deprovisionSatelliteService() RemoteException=" + ex);
1001             ex.rethrowFromSystemServer();
1002         }
1003     }
1004 
1005     /**
1006      * Registers for the satellite provision state changed.
1007      *
1008      * @param executor The executor on which the callback will be called.
1009      * @param callback The callback to handle the satellite provision state changed event.
1010      *
1011      * @return The {@link SatelliteError} result of the operation.
1012      *
1013      * @throws SecurityException if the caller doesn't have required permission.
1014      * @throws IllegalStateException if the Telephony process is not currently available.
1015      */
1016     @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
1017 
registerForSatelliteProvisionStateChanged( @onNull @allbackExecutor Executor executor, @NonNull SatelliteProvisionStateCallback callback)1018     @SatelliteError public int registerForSatelliteProvisionStateChanged(
1019             @NonNull @CallbackExecutor Executor executor,
1020             @NonNull SatelliteProvisionStateCallback callback) {
1021         Objects.requireNonNull(executor);
1022         Objects.requireNonNull(callback);
1023 
1024         try {
1025             ITelephony telephony = getITelephony();
1026             if (telephony != null) {
1027                 ISatelliteProvisionStateCallback internalCallback =
1028                         new ISatelliteProvisionStateCallback.Stub() {
1029                             @Override
1030                             public void onSatelliteProvisionStateChanged(boolean provisioned) {
1031                                 executor.execute(() -> Binder.withCleanCallingIdentity(
1032                                         () -> callback.onSatelliteProvisionStateChanged(
1033                                                 provisioned)));
1034                             }
1035                         };
1036                 sSatelliteProvisionStateCallbackMap.put(callback, internalCallback);
1037                 return telephony.registerForSatelliteProvisionStateChanged(
1038                         mSubId, internalCallback);
1039             } else {
1040                 throw new IllegalStateException("telephony service is null.");
1041             }
1042         } catch (RemoteException ex) {
1043             loge("registerForSatelliteProvisionStateChanged() RemoteException: " + ex);
1044             ex.rethrowFromSystemServer();
1045         }
1046         return SATELLITE_REQUEST_FAILED;
1047     }
1048 
1049     /**
1050      * Unregisters for the satellite provision state changed.
1051      * If callback was not registered before, the request will be ignored.
1052      *
1053      * @param callback The callback that was passed to
1054      * {@link #registerForSatelliteProvisionStateChanged(Executor, SatelliteProvisionStateCallback)}
1055      *
1056      * @throws SecurityException if the caller doesn't have required permission.
1057      * @throws IllegalStateException if the Telephony process is not currently available.
1058      */
1059     @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
1060 
unregisterForSatelliteProvisionStateChanged( @onNull SatelliteProvisionStateCallback callback)1061     public void unregisterForSatelliteProvisionStateChanged(
1062             @NonNull SatelliteProvisionStateCallback callback) {
1063         Objects.requireNonNull(callback);
1064         ISatelliteProvisionStateCallback internalCallback =
1065                 sSatelliteProvisionStateCallbackMap.remove(callback);
1066 
1067         try {
1068             ITelephony telephony = getITelephony();
1069             if (telephony != null) {
1070                 if (internalCallback != null) {
1071                     telephony.unregisterForSatelliteProvisionStateChanged(mSubId, internalCallback);
1072                 } else {
1073                     loge("unregisterForSatelliteProvisionStateChanged: No internal callback.");
1074                 }
1075             } else {
1076                 throw new IllegalStateException("telephony service is null.");
1077             }
1078         } catch (RemoteException ex) {
1079             loge("unregisterForSatelliteProvisionStateChanged() RemoteException: " + ex);
1080             ex.rethrowFromSystemServer();
1081         }
1082     }
1083 
1084     /**
1085      * Request to get whether this device is provisioned with a satellite provider.
1086      *
1087      * @param executor The executor on which the callback will be called.
1088      * @param callback The callback object to which the result will be delivered.
1089      *                 If the request is successful, {@link OutcomeReceiver#onResult(Object)}
1090      *                 will return a {@code boolean} with value {@code true} if the device is
1091      *                 provisioned with a satellite provider and {@code false} otherwise.
1092      *                 If the request is not successful, {@link OutcomeReceiver#onError(Throwable)}
1093      *                 will return a {@link SatelliteException} with the {@link SatelliteError}.
1094      *
1095      * @throws SecurityException if the caller doesn't have required permission.
1096      * @throws IllegalStateException if the Telephony process is not currently available.
1097      */
1098     @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
1099 
requestIsSatelliteProvisioned(@onNull @allbackExecutor Executor executor, @NonNull OutcomeReceiver<Boolean, SatelliteException> callback)1100     public void requestIsSatelliteProvisioned(@NonNull @CallbackExecutor Executor executor,
1101             @NonNull OutcomeReceiver<Boolean, SatelliteException> callback) {
1102         Objects.requireNonNull(executor);
1103         Objects.requireNonNull(callback);
1104 
1105         try {
1106             ITelephony telephony = getITelephony();
1107             if (telephony != null) {
1108                 ResultReceiver receiver = new ResultReceiver(null) {
1109                     @Override
1110                     protected void onReceiveResult(int resultCode, Bundle resultData) {
1111                         if (resultCode == SATELLITE_ERROR_NONE) {
1112                             if (resultData.containsKey(KEY_SATELLITE_PROVISIONED)) {
1113                                 boolean isSatelliteProvisioned =
1114                                         resultData.getBoolean(KEY_SATELLITE_PROVISIONED);
1115                                 executor.execute(() -> Binder.withCleanCallingIdentity(() ->
1116                                         callback.onResult(isSatelliteProvisioned)));
1117                             } else {
1118                                 loge("KEY_SATELLITE_PROVISIONED does not exist.");
1119                                 executor.execute(() -> Binder.withCleanCallingIdentity(() ->
1120                                         callback.onError(
1121                                                 new SatelliteException(SATELLITE_REQUEST_FAILED))));
1122                             }
1123                         } else {
1124                             executor.execute(() -> Binder.withCleanCallingIdentity(() ->
1125                                     callback.onError(new SatelliteException(resultCode))));
1126                         }
1127                     }
1128                 };
1129                 telephony.requestIsSatelliteProvisioned(mSubId, receiver);
1130             } else {
1131                 throw new IllegalStateException("telephony service is null.");
1132             }
1133         } catch (RemoteException ex) {
1134             loge("requestIsSatelliteProvisioned() RemoteException: " + ex);
1135             ex.rethrowFromSystemServer();
1136         }
1137     }
1138 
1139     /**
1140      * Registers for modem state changed from satellite modem.
1141      *
1142      * @param executor The executor on which the callback will be called.
1143      * @param callback The callback to handle the satellite modem state changed event.
1144      *
1145      * @return The {@link SatelliteError} result of the operation.
1146      *
1147      * @throws SecurityException if the caller doesn't have required permission.
1148      * @throws IllegalStateException if the Telephony process is not currently available.
1149      */
1150     @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
1151 
registerForSatelliteModemStateChanged( @onNull @allbackExecutor Executor executor, @NonNull SatelliteStateCallback callback)1152     @SatelliteError public int registerForSatelliteModemStateChanged(
1153             @NonNull @CallbackExecutor Executor executor,
1154             @NonNull SatelliteStateCallback callback) {
1155         Objects.requireNonNull(executor);
1156         Objects.requireNonNull(callback);
1157 
1158         try {
1159             ITelephony telephony = getITelephony();
1160             if (telephony != null) {
1161                 ISatelliteStateCallback internalCallback = new ISatelliteStateCallback.Stub() {
1162                     @Override
1163                     public void onSatelliteModemStateChanged(int state) {
1164                         executor.execute(() -> Binder.withCleanCallingIdentity(() ->
1165                                 callback.onSatelliteModemStateChanged(state)));
1166                     }
1167                 };
1168                 sSatelliteStateCallbackMap.put(callback, internalCallback);
1169                 return telephony.registerForSatelliteModemStateChanged(mSubId, internalCallback);
1170             } else {
1171                 throw new IllegalStateException("telephony service is null.");
1172             }
1173         } catch (RemoteException ex) {
1174             loge("registerForSatelliteModemStateChanged() RemoteException:" + ex);
1175             ex.rethrowFromSystemServer();
1176         }
1177         return SATELLITE_REQUEST_FAILED;
1178     }
1179 
1180     /**
1181      * Unregisters for modem state changed from satellite modem.
1182      * If callback was not registered before, the request will be ignored.
1183      *
1184      * @param callback The callback that was passed to
1185      * {@link #registerForSatelliteModemStateChanged(Executor, SatelliteStateCallback)}.
1186      *
1187      * @throws SecurityException if the caller doesn't have required permission.
1188      * @throws IllegalStateException if the Telephony process is not currently available.
1189      */
1190     @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
1191 
unregisterForSatelliteModemStateChanged(@onNull SatelliteStateCallback callback)1192     public void unregisterForSatelliteModemStateChanged(@NonNull SatelliteStateCallback callback) {
1193         Objects.requireNonNull(callback);
1194         ISatelliteStateCallback internalCallback = sSatelliteStateCallbackMap.remove(callback);
1195 
1196         try {
1197             ITelephony telephony = getITelephony();
1198             if (telephony != null) {
1199                 if (internalCallback != null) {
1200                     telephony.unregisterForSatelliteModemStateChanged(mSubId, internalCallback);
1201                 } else {
1202                     loge("unregisterForSatelliteModemStateChanged: No internal callback.");
1203                 }
1204             } else {
1205                 throw new IllegalStateException("telephony service is null.");
1206             }
1207         } catch (RemoteException ex) {
1208             loge("unregisterForSatelliteModemStateChanged() RemoteException:" + ex);
1209             ex.rethrowFromSystemServer();
1210         }
1211     }
1212 
1213     /**
1214      * Register to receive incoming datagrams over satellite.
1215      *
1216      * @param executor The executor on which the callback will be called.
1217      * @param callback The callback to handle incoming datagrams over satellite.
1218      *                 This callback with be invoked when a new datagram is received from satellite.
1219      *
1220      * @return The {@link SatelliteError} result of the operation.
1221      *
1222      * @throws SecurityException if the caller doesn't have required permission.
1223      * @throws IllegalStateException if the Telephony process is not currently available.
1224      */
1225     @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
1226 
registerForSatelliteDatagram( @onNull @allbackExecutor Executor executor, @NonNull SatelliteDatagramCallback callback)1227     @SatelliteError public int registerForSatelliteDatagram(
1228             @NonNull @CallbackExecutor Executor executor,
1229             @NonNull SatelliteDatagramCallback callback) {
1230         Objects.requireNonNull(executor);
1231         Objects.requireNonNull(callback);
1232 
1233         try {
1234             ITelephony telephony = getITelephony();
1235             if (telephony != null) {
1236                 ISatelliteDatagramCallback internalCallback =
1237                         new ISatelliteDatagramCallback.Stub() {
1238                             @Override
1239                             public void onSatelliteDatagramReceived(long datagramId,
1240                                     @NonNull SatelliteDatagram datagram, int pendingCount,
1241                                     @NonNull IVoidConsumer internalAck) {
1242                                 Consumer<Void> externalAck = new Consumer<Void>() {
1243                                     @Override
1244                                     public void accept(Void result) {
1245                                         try {
1246                                             internalAck.accept();
1247                                         }  catch (RemoteException e) {
1248                                               logd("onSatelliteDatagramReceived "
1249                                                       + "RemoteException: " + e);
1250                                         }
1251                                     }
1252                                 };
1253 
1254                                 executor.execute(() -> Binder.withCleanCallingIdentity(
1255                                         () -> callback.onSatelliteDatagramReceived(
1256                                                 datagramId, datagram, pendingCount, externalAck)));
1257                             }
1258                         };
1259                 sSatelliteDatagramCallbackMap.put(callback, internalCallback);
1260                 return telephony.registerForSatelliteDatagram(mSubId, internalCallback);
1261             } else {
1262                 throw new IllegalStateException("telephony service is null.");
1263             }
1264         } catch (RemoteException ex) {
1265             loge("registerForSatelliteDatagram() RemoteException:" + ex);
1266             ex.rethrowFromSystemServer();
1267         }
1268         return SATELLITE_REQUEST_FAILED;
1269     }
1270 
1271     /**
1272      * Unregister to stop receiving incoming datagrams over satellite.
1273      * If callback was not registered before, the request will be ignored.
1274      *
1275      * @param callback The callback that was passed to
1276      * {@link #registerForSatelliteDatagram(Executor, SatelliteDatagramCallback)}.
1277      *
1278      * @throws SecurityException if the caller doesn't have required permission.
1279      * @throws IllegalStateException if the Telephony process is not currently available.
1280      */
1281     @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
1282 
unregisterForSatelliteDatagram(@onNull SatelliteDatagramCallback callback)1283     public void unregisterForSatelliteDatagram(@NonNull SatelliteDatagramCallback callback) {
1284         Objects.requireNonNull(callback);
1285         ISatelliteDatagramCallback internalCallback =
1286                 sSatelliteDatagramCallbackMap.remove(callback);
1287 
1288         try {
1289             ITelephony telephony = getITelephony();
1290             if (telephony != null) {
1291                 if (internalCallback != null) {
1292                     telephony.unregisterForSatelliteDatagram(mSubId, internalCallback);
1293                 } else {
1294                     loge("unregisterForSatelliteDatagram: No internal callback.");
1295                 }
1296             } else {
1297                 throw new IllegalStateException("telephony service is null.");
1298             }
1299         } catch (RemoteException ex) {
1300             loge("unregisterForSatelliteDatagram() RemoteException:" + ex);
1301             ex.rethrowFromSystemServer();
1302         }
1303     }
1304 
1305     /**
1306      * Poll pending satellite datagrams over satellite.
1307      *
1308      * This method requests modem to check if there are any pending datagrams to be received over
1309      * satellite. If there are any incoming datagrams, they will be received via
1310      * {@link SatelliteDatagramCallback#onSatelliteDatagramReceived(long, SatelliteDatagram, int,
1311      * Consumer)} )}
1312      *
1313      * @param executor The executor on which the result listener will be called.
1314      * @param resultListener Listener for the {@link SatelliteError} result of the operation.
1315      *
1316      * @throws SecurityException if the caller doesn't have required permission.
1317      * @throws IllegalStateException if the Telephony process is not currently available.
1318      */
1319     @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
1320 
pollPendingSatelliteDatagrams(@onNull @allbackExecutor Executor executor, @SatelliteError @NonNull Consumer<Integer> resultListener)1321     public void pollPendingSatelliteDatagrams(@NonNull @CallbackExecutor Executor executor,
1322             @SatelliteError @NonNull Consumer<Integer> resultListener) {
1323         Objects.requireNonNull(executor);
1324         Objects.requireNonNull(resultListener);
1325 
1326         try {
1327             ITelephony telephony = getITelephony();
1328             if (telephony != null) {
1329                 IIntegerConsumer internalCallback = new IIntegerConsumer.Stub() {
1330                     @Override
1331                     public void accept(int result) {
1332                         executor.execute(() -> Binder.withCleanCallingIdentity(
1333                                 () -> resultListener.accept(result)));
1334                     }
1335                 };
1336                 telephony.pollPendingSatelliteDatagrams(mSubId, internalCallback);
1337             } else {
1338                 throw new IllegalStateException("telephony service is null.");
1339             }
1340         } catch (RemoteException ex) {
1341             loge("pollPendingSatelliteDatagrams() RemoteException:" + ex);
1342             ex.rethrowFromSystemServer();
1343         }
1344     }
1345 
1346     /**
1347      * Send datagram over satellite.
1348      *
1349      * Gateway encodes SOS message or location sharing message into a datagram and passes it as
1350      * input to this method. Datagram received here will be passed down to modem without any
1351      * encoding or encryption.
1352      *
1353      * @param datagramType datagram type indicating whether the datagram is of type
1354      *                     SOS_SMS or LOCATION_SHARING.
1355      * @param datagram encoded gateway datagram which is encrypted by the caller.
1356      *                 Datagram will be passed down to modem without any encoding or encryption.
1357      * @param needFullScreenPointingUI If set to true, this indicates pointingUI app to open in full
1358      *                                 screen mode if satellite communication needs pointingUI.
1359      *                                 If this is set to false, pointingUI may be presented to the
1360      *                                 user in collapsed view. Application may decide to mark this
1361      *                                 flag as true when the user is sending data for the first time
1362      *                                 or whenever there is a considerable idle time between
1363      *                                 satellite activity. This decision should be done based upon
1364      *                                 user activity and the application's ability to determine the
1365      *                                 best possible UX experience for the user.
1366      * @param executor The executor on which the result listener will be called.
1367      * @param resultListener Listener for the {@link SatelliteError} result of the operation.
1368      *
1369      * @throws SecurityException if the caller doesn't have required permission.
1370      * @throws IllegalStateException if the Telephony process is not currently available.
1371      */
1372     @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
1373 
sendSatelliteDatagram(@atagramType int datagramType, @NonNull SatelliteDatagram datagram, boolean needFullScreenPointingUI, @NonNull @CallbackExecutor Executor executor, @SatelliteError @NonNull Consumer<Integer> resultListener)1374     public void sendSatelliteDatagram(@DatagramType int datagramType,
1375             @NonNull SatelliteDatagram datagram, boolean needFullScreenPointingUI,
1376             @NonNull @CallbackExecutor Executor executor,
1377             @SatelliteError @NonNull Consumer<Integer> resultListener) {
1378         Objects.requireNonNull(datagram);
1379         Objects.requireNonNull(executor);
1380         Objects.requireNonNull(resultListener);
1381 
1382         try {
1383             ITelephony telephony = getITelephony();
1384             if (telephony != null) {
1385                 IIntegerConsumer internalCallback = new IIntegerConsumer.Stub() {
1386                     @Override
1387                     public void accept(int result) {
1388                         executor.execute(() -> Binder.withCleanCallingIdentity(
1389                                 () -> resultListener.accept(result)));
1390                     }
1391                 };
1392                 telephony.sendSatelliteDatagram(mSubId, datagramType, datagram,
1393                         needFullScreenPointingUI, internalCallback);
1394             } else {
1395                 throw new IllegalStateException("telephony service is null.");
1396             }
1397         } catch (RemoteException ex) {
1398             loge("sendSatelliteDatagram() RemoteException:" + ex);
1399             ex.rethrowFromSystemServer();
1400         }
1401     }
1402 
1403     /**
1404      * Request to get whether satellite communication is allowed for the current location.
1405      *
1406      * @param executor The executor on which the callback will be called.
1407      * @param callback The callback object to which the result will be delivered.
1408      *                 If the request is successful, {@link OutcomeReceiver#onResult(Object)}
1409      *                 will return a {@code boolean} with value {@code true} if satellite
1410      *                 communication is allowed for the current location and
1411      *                 {@code false} otherwise.
1412      *                 If the request is not successful, {@link OutcomeReceiver#onError(Throwable)}
1413      *                 will return a {@link SatelliteException} with the {@link SatelliteError}.
1414      *
1415      * @throws SecurityException if the caller doesn't have required permission.
1416      * @throws IllegalStateException if the Telephony process is not currently available.
1417      */
1418     @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
1419 
requestIsSatelliteCommunicationAllowedForCurrentLocation( @onNull @allbackExecutor Executor executor, @NonNull OutcomeReceiver<Boolean, SatelliteException> callback)1420     public void requestIsSatelliteCommunicationAllowedForCurrentLocation(
1421             @NonNull @CallbackExecutor Executor executor,
1422             @NonNull OutcomeReceiver<Boolean, SatelliteException> callback) {
1423         Objects.requireNonNull(executor);
1424         Objects.requireNonNull(callback);
1425 
1426         try {
1427             ITelephony telephony = getITelephony();
1428             if (telephony != null) {
1429                 ResultReceiver receiver = new ResultReceiver(null) {
1430                     @Override
1431                     protected void onReceiveResult(int resultCode, Bundle resultData) {
1432                         if (resultCode == SATELLITE_ERROR_NONE) {
1433                             if (resultData.containsKey(KEY_SATELLITE_COMMUNICATION_ALLOWED)) {
1434                                 boolean isSatelliteCommunicationAllowed =
1435                                         resultData.getBoolean(KEY_SATELLITE_COMMUNICATION_ALLOWED);
1436                                 executor.execute(() -> Binder.withCleanCallingIdentity(() ->
1437                                         callback.onResult(isSatelliteCommunicationAllowed)));
1438                             } else {
1439                                 loge("KEY_SATELLITE_COMMUNICATION_ALLOWED does not exist.");
1440                                 executor.execute(() -> Binder.withCleanCallingIdentity(() ->
1441                                         callback.onError(
1442                                                 new SatelliteException(SATELLITE_REQUEST_FAILED))));
1443                             }
1444                         } else {
1445                             executor.execute(() -> Binder.withCleanCallingIdentity(() ->
1446                                     callback.onError(new SatelliteException(resultCode))));
1447                         }
1448                     }
1449                 };
1450                 telephony.requestIsSatelliteCommunicationAllowedForCurrentLocation(mSubId,
1451                         receiver);
1452             } else {
1453                 throw new IllegalStateException("telephony service is null.");
1454             }
1455         } catch (RemoteException ex) {
1456             loge("requestIsSatelliteCommunicationAllowedForCurrentLocation() RemoteException: "
1457                     + ex);
1458             ex.rethrowFromSystemServer();
1459         }
1460     }
1461 
1462     /**
1463      * Request to get the duration in seconds after which the satellite will be visible.
1464      * This will be {@link Duration#ZERO} if the satellite is currently visible.
1465      *
1466      * @param executor The executor on which the callback will be called.
1467      * @param callback The callback object to which the result will be delivered.
1468      *                 If the request is successful, {@link OutcomeReceiver#onResult(Object)}
1469      *                 will return the time after which the satellite will be visible.
1470      *                 If the request is not successful, {@link OutcomeReceiver#onError(Throwable)}
1471      *                 will return a {@link SatelliteException} with the {@link SatelliteError}.
1472      *
1473      * @throws SecurityException if the caller doesn't have required permission.
1474      * @throws IllegalStateException if the Telephony process is not currently available.
1475      */
1476     @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
1477 
requestTimeForNextSatelliteVisibility(@onNull @allbackExecutor Executor executor, @NonNull OutcomeReceiver<Duration, SatelliteException> callback)1478     public void requestTimeForNextSatelliteVisibility(@NonNull @CallbackExecutor Executor executor,
1479             @NonNull OutcomeReceiver<Duration, SatelliteException> callback) {
1480         Objects.requireNonNull(executor);
1481         Objects.requireNonNull(callback);
1482 
1483         try {
1484             ITelephony telephony = getITelephony();
1485             if (telephony != null) {
1486                 ResultReceiver receiver = new ResultReceiver(null) {
1487                     @Override
1488                     protected void onReceiveResult(int resultCode, Bundle resultData) {
1489                         if (resultCode == SATELLITE_ERROR_NONE) {
1490                             if (resultData.containsKey(KEY_SATELLITE_NEXT_VISIBILITY)) {
1491                                 int nextVisibilityDuration =
1492                                         resultData.getInt(KEY_SATELLITE_NEXT_VISIBILITY);
1493                                 executor.execute(() -> Binder.withCleanCallingIdentity(() ->
1494                                         callback.onResult(
1495                                                 Duration.ofSeconds(nextVisibilityDuration))));
1496                             } else {
1497                                 loge("KEY_SATELLITE_NEXT_VISIBILITY does not exist.");
1498                                 executor.execute(() -> Binder.withCleanCallingIdentity(() ->
1499                                         callback.onError(
1500                                                 new SatelliteException(SATELLITE_REQUEST_FAILED))));
1501                             }
1502                         } else {
1503                             executor.execute(() -> Binder.withCleanCallingIdentity(() ->
1504                                     callback.onError(new SatelliteException(resultCode))));
1505                         }
1506                     }
1507                 };
1508                 telephony.requestTimeForNextSatelliteVisibility(mSubId, receiver);
1509             } else {
1510                 throw new IllegalStateException("telephony service is null.");
1511             }
1512         } catch (RemoteException ex) {
1513             loge("requestTimeForNextSatelliteVisibility() RemoteException: " + ex);
1514             ex.rethrowFromSystemServer();
1515         }
1516     }
1517 
1518     /**
1519      * Inform whether the device is aligned with the satellite for demo mode.
1520      *
1521      * @param isAligned {@true} Device is aligned with the satellite for demo mode
1522      *                  {@false} Device is not aligned with the satellite for demo mode
1523      *
1524      * @throws SecurityException if the caller doesn't have required permission.
1525      * @throws IllegalStateException if the Telephony process is not currently available.
1526      */
1527     @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
1528 
onDeviceAlignedWithSatellite(boolean isAligned)1529     public void onDeviceAlignedWithSatellite(boolean isAligned) {
1530         try {
1531             ITelephony telephony = getITelephony();
1532             if (telephony != null) {
1533                 telephony.onDeviceAlignedWithSatellite(mSubId, isAligned);
1534             } else {
1535                 throw new IllegalStateException("telephony service is null.");
1536             }
1537         } catch (RemoteException ex) {
1538             loge("informDeviceAlignedToSatellite() RemoteException:" + ex);
1539             ex.rethrowFromSystemServer();
1540         }
1541     }
1542 
getITelephony()1543     private static ITelephony getITelephony() {
1544         ITelephony binder = ITelephony.Stub.asInterface(TelephonyFrameworkInitializer
1545                 .getTelephonyServiceManager()
1546                 .getTelephonyServiceRegisterer()
1547                 .get());
1548         if (binder == null) {
1549             throw new RuntimeException("Could not find Telephony Service.");
1550         }
1551         return binder;
1552     }
1553 
logd(@onNull String log)1554     private static void logd(@NonNull String log) {
1555         Rlog.d(TAG, log);
1556     }
1557 
loge(@onNull String log)1558     private static void loge(@NonNull String log) {
1559         Rlog.e(TAG, log);
1560     }
1561 }
1562