Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d8c23e3f authored by Aishwarya Mallampati's avatar Aishwarya Mallampati
Browse files

Added Satellite Messaging APIs.

The following apis are added in this CL:
- registerForSatelliteStateChange()
- unregisterForSatelliteStateChange()
- registerForSatelliteDatagram()
- unregisterForSatelliteDatagram()
- getPendingSatelliteDatagrams()

Bug: 260896985
Test: atest SatelliteManagerTest
Change-Id: Ice9e97f61a6adffbab8ee53dea3b54a8d12ce174
parent 420f13f2
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
package android.telephony.satellite;

import android.telephony.satellite.PointingInfo;
import android.telephony.satellite.SatelliteDatagram;

/**
 * Interface for satellite state listener.
@@ -26,4 +27,7 @@ oneway interface ISatelliteStateListener {
    void onSatelliteProvisionStateChanged(in int[] features, in boolean provisioned);
    void onSatellitePositionUpdate(in PointingInfo pointingInfo);
    void onMessageTransferStateUpdate(in int state);
    void onSatelliteModemStateChange(in int state);
    void onPendingMessageCount(in int count);
    void onSatelliteDatagrams(in SatelliteDatagram[] datagrams);
}
+60 −0
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@ import android.os.Binder;
import android.telephony.satellite.stub.SatelliteImplBase;

import java.lang.ref.WeakReference;
import java.util.List;
import java.util.concurrent.Executor;

/**
@@ -91,6 +92,34 @@ public class SatelliteCallback {
                @SatelliteManager.SatelliteMessageTransferState int state);
    }

    /**
     * Interface for satellite state change listener.
     */
    public interface SatelliteStateListener {
        /**
         * Called when satellite state changes.
         * @param state - The new satellite state.
         */
        void onSatelliteModemStateChange(@SatelliteManager.SatelliteModemState int state);

        /**
         * Called when there are pending messages to be received from satellite.
         * @param count - pending message count.
         */
        void onPendingMessageCount(int count);
    }

    /**
     * Interface for satellite datagram listener.
     */
    public interface SatelliteDatagramListener {
        /**
         * Called when there are incoming datagrams to be received.
         * @param datagrams - datagrams to be received over satellite.
         */
        void onSatelliteDatagrams(SatelliteDatagram[] datagrams);
    }

    private static class ISatelliteStateListenerStub extends ISatelliteStateListener.Stub {
        private WeakReference<SatelliteCallback> mSatelliteCallbackWeakRef;
        private Executor mExecutor;
@@ -128,5 +157,36 @@ public class SatelliteCallback {
            Binder.withCleanCallingIdentity(() -> mExecutor.execute(
                    () -> listener.onMessageTransferStateUpdate(state)));
        }


        @Override
        public void onSatelliteModemStateChange(@SatelliteManager.SatelliteModemState int state) {
            SatelliteStateListener listener =
                    (SatelliteStateListener) mSatelliteCallbackWeakRef.get();
            if (listener == null) return;

            Binder.withCleanCallingIdentity(() -> mExecutor.execute(
                    () -> listener.onSatelliteModemStateChange(state)));
        }

        @Override
        public void onPendingMessageCount(int count) {
            SatelliteStateListener listener =
                    (SatelliteStateListener) mSatelliteCallbackWeakRef.get();
            if (listener == null) return;

            Binder.withCleanCallingIdentity(() -> mExecutor.execute(
                    () -> listener.onPendingMessageCount(count)));
        }

        @Override
        public void onSatelliteDatagrams(SatelliteDatagram[] datagrams) {
            SatelliteDatagramListener listener =
                    (SatelliteDatagramListener) mSatelliteCallbackWeakRef.get();
            if (listener == null) return;

            Binder.withCleanCallingIdentity(() -> mExecutor.execute(
                    () -> listener.onSatelliteDatagrams(datagrams)));
        }
    }
}
+19 −0
Original line number Diff line number Diff line
/*
 * Copyright 2023, The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package android.telephony.satellite;

parcelable SatelliteDatagram;
+75 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2023 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package android.telephony.satellite;

import android.annotation.NonNull;
import android.annotation.Nullable;
import android.os.Parcel;
import android.os.Parcelable;

/**
 * @hide
 */
public final class SatelliteDatagram implements Parcelable {
    /**
     * Datagram to be sent or received over satellite.
     */
    private byte[] mData;

    /**
     * @hide
     */
    public SatelliteDatagram(@NonNull byte[] data) {
        mData = data;
    }

    private SatelliteDatagram(Parcel in) {
        readFromParcel(in);
    }

    @Override
    public int describeContents() {
        return 0;
    }

    @Override
    public void writeToParcel(@NonNull Parcel out, int flags) {
        out.writeByteArray(mData);
    }

    public static final @android.annotation.NonNull Creator<SatelliteDatagram> CREATOR =
            new Creator<SatelliteDatagram>() {
                @Override
                public SatelliteDatagram createFromParcel(Parcel in) {
                    return new SatelliteDatagram(in);
                }

                @Override
                public SatelliteDatagram[] newArray(int size) {
                    return new SatelliteDatagram[size];
                }
            };

    @Nullable
    public byte[] getSatelliteDatagram() {
        return mData;
    }

    private void readFromParcel(Parcel in) {
        mData = in.createByteArray();
    }
}
+203 −0
Original line number Diff line number Diff line
@@ -490,6 +490,44 @@ public class SatelliteManager {
    })
    public @interface SatelliteMessageTransferState {}

    /* Satellite modem is in idle state. */
    public static final int SATELLITE_MODEM_STATE_IDLE = 0;

    /* Satellite modem is listening for incoming messages. */
    public static final int SATELLITE_MODEM_STATE_LISTENING = 1;

    /* Satellite modem is sending and/or receiving messages. */
    public static final int SATELLITE_MODEM_STATE_MESSAGE_TRANSFERRING = 2;

    /* Satellite modem is powered off */
    public static final int SATELLITE_MODEM_STATE_OFF = 3;

    /** @hide */
    @IntDef(prefix = {"SATELLITE_STATE_"},
            value = {
                    SATELLITE_MODEM_STATE_IDLE,
                    SATELLITE_MODEM_STATE_LISTENING,
                    SATELLITE_MODEM_STATE_MESSAGE_TRANSFERRING,
                    SATELLITE_MODEM_STATE_OFF
            })
    @Retention(RetentionPolicy.SOURCE)
    public @interface SatelliteModemState {}

    /** SOS SMS */
    public static final int DATAGRAM_TYPE_SOS_SMS = 0;

    /** Location sharing message */
    public static final int DATAGRAM_TYPE_LOCATION_SHARING = 3;

    @IntDef(
            prefix = "DATAGRAM_TYPE_",
            value = {
                    DATAGRAM_TYPE_SOS_SMS,
                    DATAGRAM_TYPE_LOCATION_SHARING,
            })
    @Retention(RetentionPolicy.SOURCE)
    public @interface DatagramType {}

    /**
     * Start receiving satellite position updates.
     * This can be called by the pointing UI when the user starts pointing to the satellite.
@@ -824,6 +862,171 @@ public class SatelliteManager {
        }
    }

    /**
     * Register for listening to satellite modem state changes.
     *
     * @param executor - The executor on which the callback will be called.
     * @param callback - The callback to handle the satellite state change event. This
     *                 SatelliteCallback should implement the interface
     *                 {@link SatelliteCallback.SatelliteStateListener}.
     *
     * @return The error code of the request.
     * @throws SecurityException if the caller doesn't have required permission.
     * @throws IllegalStateException if the Telephony process is not currently available.
     */
    @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
    @SatelliteError
    public int registerForSatelliteModemStateChange(@NonNull @CallbackExecutor Executor executor,
            @NonNull SatelliteCallback callback) {
        Objects.requireNonNull(executor);
        Objects.requireNonNull(callback);

        try {
            ITelephony telephony = getITelephony();
            if (telephony != null) {
                callback.init(executor);
                return telephony.registerForSatelliteModemStateChange(mSubId,
                        callback.getCallbackStub());
            } else {
                throw new IllegalStateException("telephony service is null.");
            }
        } catch (RemoteException ex) {
            loge("registerForSatelliteModemStateChange() RemoteException:" + ex);
            ex.rethrowFromSystemServer();
        }
        return SATELLITE_REQUEST_FAILED;
    }

    /**
     * Unregister to stop listening to satellite modem state changes.
     *
     * @param callback - The callback that was passed to
     * {@link #registerForSatelliteModemStateChange(Executor, SatelliteCallback)}
     *
     * @return The error code of the request.
     * @throws SecurityException if the caller doesn't have required permission.
     * @throws IllegalStateException if the Telephony process is not currently available.
     */
    @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
    @SatelliteError
    public int unregisterForSatelliteModemStateChange(@NonNull SatelliteCallback callback) {
        Objects.requireNonNull(callback);

        if (callback.getCallbackStub() == null) {
            loge("unregisterForSatelliteModemStateChange: callbackStub is null");
            return SATELLITE_INVALID_ARGUMENTS;
        }

        try {
            ITelephony telephony = getITelephony();
            if (telephony != null) {
                return telephony.unregisterForSatelliteModemStateChange(mSubId,
                        callback.getCallbackStub());
            } else {
                throw new IllegalStateException("telephony service is null.");
            }
        } catch (RemoteException ex) {
            loge("unregisterForSatelliteModemStateChange() RemoteException:" + ex);
            ex.rethrowFromSystemServer();
        }
        return SATELLITE_REQUEST_FAILED;
    }

    /**
     * Register to receive incoming datagrams over satellite.
     *
     * @param datagramType - type of datagram
     * @param executor - The executor on which the callback will be called.
     * @param callback - The callback to handle incoming datagrams over satellite. This
     *                 SatelliteCallback should implement the interface
     *                 {@link SatelliteCallback.SatelliteDatagramListener}.
     *
     * @return The error code of the request.
     * @throws SecurityException if the caller doesn't have required permission.
     * @throws IllegalStateException if the Telephony process is not currently available.
     */
    @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
    @SatelliteError
    public int registerForSatelliteDatagram(@DatagramType int datagramType,
            @NonNull @CallbackExecutor Executor executor, @NonNull SatelliteCallback callback) {
        Objects.requireNonNull(executor);
        Objects.requireNonNull(callback);

        try {
            ITelephony telephony = getITelephony();
            if (telephony != null) {
                callback.init(executor);
                return telephony.registerForSatelliteDatagram(mSubId, datagramType,
                            callback.getCallbackStub());
            } else {
                throw new IllegalStateException("telephony service is null.");
            }
        } catch (RemoteException ex) {
            loge("registerForSatelliteDatagram() RemoteException:" + ex);
            ex.rethrowFromSystemServer();
        }
        return SATELLITE_REQUEST_FAILED;
    }

    /**
     * Unregister to stop receiving incoming datagrams over satellite.
     *
     * @param callback - The callback that was passed to
     * {@link #registerForSatelliteDatagram(int, Executor, SatelliteCallback)}
     *
     * @return The error code of the request.
     * @throws SecurityException if the caller doesn't have required permission.
     * @throws IllegalStateException if the Telephony process is not currently available.
     */
    @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
    @SatelliteError
    public int unregisterForSatelliteDatagram(@NonNull SatelliteCallback callback) {
        Objects.requireNonNull(callback);

        if (callback.getCallbackStub() == null) {
            loge("unregisterForSatelliteDatagram: callbackStub is null");
            return SATELLITE_INVALID_ARGUMENTS;
        }

        try {
            ITelephony telephony = getITelephony();
            if (telephony != null) {
                return telephony.unregisterForSatelliteDatagram(mSubId,
                        callback.getCallbackStub());
            } else {
                throw new IllegalStateException("telephony service is null.");
            }
        } catch (RemoteException ex) {
            loge("unregisterForSatelliteDatagram() RemoteException:" + ex);
            ex.rethrowFromSystemServer();
        }
        return SATELLITE_REQUEST_FAILED;
    }

    /**
     * Poll pending satellite datagrams over satellite.
     *
     * @return The result of the operation.
     * @throws SecurityException if the caller doesn't have required permission.
     * @throws IllegalStateException if the Telephony process is not currently available.
     */
    @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
    @SatelliteError
    public int pollPendingSatelliteDatagrams() {
        try {
            ITelephony telephony = getITelephony();
            if (telephony != null) {
                return telephony.pollPendingSatelliteDatagrams(mSubId);
            } else {
                throw new IllegalStateException("telephony service is null.");
            }
        } catch (RemoteException ex) {
            loge("pollPendingSatelliteDatagrams() RemoteException:" + ex);
            ex.rethrowFromSystemServer();
        }
        return SATELLITE_REQUEST_FAILED;
    }

    private static ITelephony getITelephony() {
        ITelephony binder = ITelephony.Stub.asInterface(TelephonyFrameworkInitializer
                .getTelephonyServiceManager()
Loading