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