Add support for satellite pointing APIs
Test: atest SatelliteManagerTest
Bug: 266249740
Change-Id: Ie4b10dcf4762d86ea1560ed61647785559dcd43d
diff --git a/src/com/android/phone/PhoneInterfaceManager.java b/src/com/android/phone/PhoneInterfaceManager.java
index b7dfb77..d754d4c 100644
--- a/src/com/android/phone/PhoneInterfaceManager.java
+++ b/src/com/android/phone/PhoneInterfaceManager.java
@@ -143,6 +143,9 @@
import android.telephony.ims.feature.ImsFeature;
import android.telephony.ims.stub.ImsConfigImplBase;
import android.telephony.ims.stub.ImsRegistrationImplBase;
+import android.telephony.satellite.ISatellitePositionUpdateCallback;
+import android.telephony.satellite.PointingInfo;
+import android.telephony.satellite.SatelliteManager;
import android.text.TextUtils;
import android.util.ArraySet;
import android.util.EventLog;
@@ -185,6 +188,7 @@
import com.android.internal.telephony.ProxyController;
import com.android.internal.telephony.RIL;
import com.android.internal.telephony.RILConstants;
+import com.android.internal.telephony.RILUtils;
import com.android.internal.telephony.RadioInterfaceCapabilityController;
import com.android.internal.telephony.ServiceStateTracker;
import com.android.internal.telephony.SmsApplication;
@@ -251,6 +255,7 @@
import java.util.Objects;
import java.util.Set;
import java.util.UUID;
+import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Consumer;
@@ -376,6 +381,10 @@
private static final int EVENT_IS_VONR_ENABLED_DONE = 116;
private static final int CMD_PURCHASE_PREMIUM_CAPABILITY = 117;
private static final int EVENT_PURCHASE_PREMIUM_CAPABILITY_DONE = 118;
+ private static final int CMD_START_SATELLITE_POSITION_UPDATES = 119;
+ private static final int EVENT_START_SATELLITE_POSITION_UPDATES_DONE = 120;
+ private static final int CMD_STOP_SATELLITE_POSITION_UPDATES = 121;
+ private static final int EVENT_STOP_SATELLITE_POSITION_UPDATES_DONE = 122;
// Parameters of select command.
private static final int SELECT_COMMAND = 0xA4;
private static final int SELECT_P1 = 0x04;
@@ -406,6 +415,8 @@
private static final int USER_ACTIVITY_NOTIFICATION_DELAY = 200;
private Set<Integer> mCarrierPrivilegeTestOverrideSubIds = new ArraySet<>();
+ private Map<Integer, SatellitePositionUpdateHandler> mSatellitePositionUpdateHandlers =
+ new ConcurrentHashMap<>();
private static final String PREF_CARRIERS_ALPHATAG_PREFIX = "carrier_alphtag_";
private static final String PREF_CARRIERS_NUMBER_PREFIX = "carrier_number_";
@@ -501,6 +512,46 @@
}
}
+ private static final class SatellitePositionUpdateHandler extends Handler {
+ public static final int EVENT_POSITION_UPDATE = 1;
+ public static final int EVENT_MESSAGE_TRANSFER_STATE_UPDATE = 2;
+
+ private final ISatellitePositionUpdateCallback mCallback;
+
+ SatellitePositionUpdateHandler(ISatellitePositionUpdateCallback callback, Looper looper) {
+ super(looper);
+ mCallback = callback;
+ }
+
+ @Override
+ public void handleMessage(@NonNull Message msg) {
+ switch (msg.what) {
+ case EVENT_POSITION_UPDATE: {
+ AsyncResult ar = (AsyncResult) msg.obj;
+ PointingInfo pointingInfo = (PointingInfo) ar.result;
+ try {
+ mCallback.onSatellitePositionUpdate(pointingInfo);
+ } catch (RemoteException e) {
+ loge("EVENT_POSITION_UPDATE RemoteException: " + e);
+ }
+ break;
+ }
+ case EVENT_MESSAGE_TRANSFER_STATE_UPDATE: {
+ AsyncResult ar = (AsyncResult) msg.obj;
+ int state = (int) ar.result;
+ try {
+ mCallback.onMessageTransferStateUpdate(state);
+ } catch (RemoteException e) {
+ loge("EVENT_MESSAGE_TRANSFER_STATE_UPDATE RemoteException: " + e);
+ }
+ break;
+ }
+ default:
+ loge("SatellitePositionUpdateHandler unknown event: " + msg.what);
+ }
+ }
+ }
+
/**
* A request object for use with {@link MainThreadHandler}. Requesters should wait() on the
* request after sending. The main thread will notify the request when it is complete.
@@ -2247,6 +2298,76 @@
notifyRequester(request);
break;
+ case CMD_START_SATELLITE_POSITION_UPDATES: {
+ request = (MainThreadRequest) msg.obj;
+ onCompleted =
+ obtainMessage(EVENT_START_SATELLITE_POSITION_UPDATES_DONE, request);
+ Phone phone = getPhoneFromRequest(request);
+ if (phone != null) {
+ phone.startSatellitePositionUpdates(onCompleted);
+ } else {
+ loge("startSatellitePositionUpdates: No phone object");
+ request.result = SatelliteManager.SATELLITE_SERVICE_REQUEST_FAILED;
+ notifyRequester(request);
+ }
+ break;
+ }
+
+ case EVENT_START_SATELLITE_POSITION_UPDATES_DONE: {
+ ar = (AsyncResult) msg.obj;
+ request = (MainThreadRequest) ar.userObj;
+ if (ar.exception == null) {
+ request.result = SatelliteManager.SATELLITE_SERVICE_SUCCESS;
+ } else {
+ request.result = SatelliteManager.SATELLITE_SERVICE_ERROR;
+ if (ar.exception instanceof CommandException) {
+ CommandException.Error error =
+ ((CommandException) (ar.exception)).getCommandError();
+ request.result = RILUtils.convertToSatelliteError(error);
+ loge("startSatellitePositionUpdates CommandException: " + ar.exception);
+ } else {
+ loge("startSatellitePositionUpdates unknown exception:" + ar.exception);
+ }
+ }
+ notifyRequester(request);
+ break;
+ }
+
+ case CMD_STOP_SATELLITE_POSITION_UPDATES: {
+ request = (MainThreadRequest) msg.obj;
+ onCompleted =
+ obtainMessage(EVENT_STOP_SATELLITE_POSITION_UPDATES_DONE, request);
+ Phone phone = getPhoneFromRequest(request);
+ if (phone != null) {
+ phone.stopSatellitePositionUpdates(onCompleted);
+ } else {
+ loge("stopSatellitePositionUpdates: No phone object");
+ request.result = SatelliteManager.SATELLITE_SERVICE_REQUEST_FAILED;
+ notifyRequester(request);
+ }
+ break;
+ }
+
+ case EVENT_STOP_SATELLITE_POSITION_UPDATES_DONE: {
+ ar = (AsyncResult) msg.obj;
+ request = (MainThreadRequest) ar.userObj;
+ if (ar.exception == null) {
+ request.result = SatelliteManager.SATELLITE_SERVICE_SUCCESS;
+ } else {
+ request.result = SatelliteManager.SATELLITE_SERVICE_ERROR;
+ if (ar.exception instanceof CommandException) {
+ CommandException.Error error =
+ ((CommandException) (ar.exception)).getCommandError();
+ request.result = RILUtils.convertToSatelliteError(error);
+ loge("stopSatellitePositionUpdates CommandException: " + ar.exception);
+ } else {
+ loge("stopSatellitePositionUpdates unknown exception:" + ar.exception);
+ }
+ }
+ notifyRequester(request);
+ break;
+ }
+
default:
Log.w(LOG_TAG, "MainThreadHandler: unexpected message code: " + msg.what);
break;
@@ -12038,6 +12159,94 @@
}
/**
+ * Start receiving satellite position updates.
+ * This can be called by the pointing UI when the user starts pointing to the satellite.
+ * Modem should continue to report the pointing input as the device or satellite moves.
+ *
+ * @param subId The subId to start satellite position updates for.
+ * @param callbackId The callback ID associating the public SatellitePositionUpdateCallback to
+ * the internal ISatellitePositionUpdateCallback below.
+ * @param callback The callback to notify of changes in satellite position.
+ * @return The result of the operation.
+ */
+ @Override
+ @SatelliteManager.SatelliteServiceResult public int startSatellitePositionUpdates(int subId,
+ int callbackId, @NonNull ISatellitePositionUpdateCallback callback) {
+ // TODO: check for SATELLITE_COMMUNICATION permission
+ Phone phone = getPhone(subId);
+ if (phone == null) {
+ loge("startSatellitePositionUpdates called with invalid subId: " + subId
+ + ". Retrying with default phone.");
+ phone = getDefaultPhone();
+ if (phone == null) {
+ loge("startSatellitePositionUpdates failed with no phone object.");
+ return SatelliteManager.SATELLITE_SERVICE_REQUEST_FAILED;
+ }
+ }
+
+ if (mSatellitePositionUpdateHandlers.containsKey(callbackId)) {
+ log("startSatellitePositionUpdates: callback already registered: " + callbackId);
+ return SatelliteManager.SATELLITE_SERVICE_SUCCESS;
+ }
+
+ SatellitePositionUpdateHandler handler =
+ new SatellitePositionUpdateHandler(callback, Looper.getMainLooper());
+ phone.registerForSatellitePointingInfoChanged(handler,
+ SatellitePositionUpdateHandler.EVENT_POSITION_UPDATE, null);
+ phone.registerForSatelliteMessagesTransferComplete(handler,
+ SatellitePositionUpdateHandler.EVENT_MESSAGE_TRANSFER_STATE_UPDATE, null);
+ mSatellitePositionUpdateHandlers.put(callbackId, handler);
+
+ int result = (int) sendRequest(CMD_START_SATELLITE_POSITION_UPDATES, null, subId);
+ if (DBG) log("startSatellitePositionUpdates result: " + result);
+ return result;
+ }
+
+ /**
+ * Stop receiving satellite position updates.
+ * This can be called by the pointing UI when the user stops pointing to the satellite.
+ *
+ * @param subId The subId to stop satellite position updates for.
+ * @param callbackId The ID of the callback that was passed in {@link
+ * #startSatellitePositionUpdates(int, int, ISatellitePositionUpdateCallback)}
+ * @return The result of the operation.
+ */
+ @Override
+ @SatelliteManager.SatelliteServiceResult public int stopSatellitePositionUpdates(int subId,
+ int callbackId) {
+ // TODO: check for SATELLITE_COMMUNICATION permission
+ Phone phone = getPhone(subId);
+ if (phone == null) {
+ loge("stopSatellitePositionUpdates called with invalid subId: " + subId
+ + ". Retrying with default phone.");
+ phone = getDefaultPhone();
+ if (phone == null) {
+ loge("stopSatellitePositionUpdates failed with no phone object.");
+ return SatelliteManager.SATELLITE_SERVICE_REQUEST_FAILED;
+ }
+ }
+
+ SatellitePositionUpdateHandler handler =
+ mSatellitePositionUpdateHandlers.remove(callbackId);
+ if (handler == null) {
+ loge("stopSatellitePositionUpdates: No SatellitePositionArgument");
+ return SatelliteManager.SATELLITE_SERVICE_REQUEST_FAILED;
+ } else {
+ phone.unregisterForSatellitePointingInfoChanged(handler);
+ phone.unregisterForSatelliteMessagesTransferComplete(handler);
+ }
+
+ if (!mSatellitePositionUpdateHandlers.isEmpty()) {
+ log("stopSatellitePositionUpdates: other listeners still exist.");
+ return SatelliteManager.SATELLITE_SERVICE_SUCCESS;
+ }
+
+ int result = (int) sendRequest(CMD_STOP_SATELLITE_POSITION_UPDATES, null, subId);
+ if (DBG) log("stopSatellitePositionUpdates result: " + result);
+ return result;
+ }
+
+ /**
* Check whether the caller (or self, if not processing an IPC) can read device identifiers.
*
* <p>This method behaves in one of the following ways: