Merge "Apply telephony_config_json_parser for satellite accesss control" into main
diff --git a/satellite_client/src/android/telephony/satellite/wrapper/EarfcnRangeWrapper.java b/satellite_client/src/android/telephony/satellite/wrapper/EarfcnRangeWrapper.java
new file mode 100644
index 0000000..b2f9821
--- /dev/null
+++ b/satellite_client/src/android/telephony/satellite/wrapper/EarfcnRangeWrapper.java
@@ -0,0 +1,139 @@
+/*
+ * Copyright (C) 2024 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.wrapper;
+
+import android.annotation.FlaggedApi;
+import android.annotation.IntRange;
+import android.annotation.NonNull;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import com.android.internal.telephony.flags.Flags;
+
+import java.util.Objects;
+
+/**
+ * EARFCN (E-UTRA Absolute Radio Frequency Channel Number):  A number that identifies a
+ * specific frequency channel in LTE/5G NR, used to define the carrier frequency.
+ * The range can be [0 ~ 65535] according to the 3GPP TS 36.101
+ *
+ * In satellite communication:
+ * - Efficient frequency allocation across a wide coverage area.
+ * - Handles Doppler shift due to satellite movement.
+ * - Manages interference with terrestrial networks.
+ *
+ * See 3GPP TS 36.101 and 38.101-1 for details.
+ *
+ * @hide
+ */
+public class EarfcnRangeWrapper implements Parcelable {
+
+    /**
+     * The start frequency of the earfcn range and is inclusive in the range
+     */
+    private int mStartEarfcn;
+
+    /**
+     * The end frequency of the earfcn range and is inclusive in the range.
+     */
+    private int mEndEarfcn;
+
+    private EarfcnRangeWrapper(@NonNull Parcel in) {
+        readFromParcel(in);
+    }
+
+    @Override
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        dest.writeInt(mStartEarfcn);
+        dest.writeInt(mEndEarfcn);
+    }
+
+    private void readFromParcel(Parcel in) {
+        mStartEarfcn = in.readInt();
+        mEndEarfcn = in.readInt();
+    }
+
+    /**
+     * Constructor for the EarfcnRangeWrapper class.
+     * The range can be [0 ~ 65535] according to the 3GPP TS 36.101
+     *
+     * @param startEarfcn The starting earfcn value.
+     * @param endEarfcn   The ending earfcn value.
+     */
+    public EarfcnRangeWrapper(@IntRange(from = 0, to = 65535) int startEarfcn,
+            @IntRange(from = 0, to = 65535) int endEarfcn) {
+        mStartEarfcn = startEarfcn;
+        mEndEarfcn = endEarfcn;
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    @NonNull
+    public String toString() {
+        return "startEarfcn: " + mStartEarfcn + ", " + "endEarfcn: " + mEndEarfcn;
+    }
+
+    @NonNull
+    public static final Creator<EarfcnRangeWrapper> CREATOR = new Creator<EarfcnRangeWrapper>() {
+        @Override
+        public EarfcnRangeWrapper createFromParcel(Parcel in) {
+            return new EarfcnRangeWrapper(in);
+        }
+
+        @Override
+        public EarfcnRangeWrapper[] newArray(int size) {
+            return new EarfcnRangeWrapper[size];
+        }
+    };
+
+    /**
+     * Returns the starting earfcn value for this range.
+     * It can be [0 ~ 65535] according to the 3GPP TS 36.101
+     *
+     * @return The starting earfcn.
+     */
+    public @IntRange(from = 0, to = 65535) int getStartEarfcn() {
+        return mStartEarfcn;
+    }
+
+    /**
+     * Returns the ending earfcn value for this range.
+     * It can be [0 ~ 65535] according to the 3GPP TS 36.101
+     *
+     * @return The ending earfcn.
+     */
+    public @IntRange(from = 0, to = 65535) int getEndEarfcn() {
+        return mEndEarfcn;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (!(o instanceof EarfcnRangeWrapper that)) return false;
+
+        return (that.mStartEarfcn == mStartEarfcn) && (that.mEndEarfcn == mEndEarfcn);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(mStartEarfcn, mEndEarfcn);
+    }
+}
diff --git a/satellite_client/src/android/telephony/satellite/wrapper/SatelliteAccessConfigurationWrapper.java b/satellite_client/src/android/telephony/satellite/wrapper/SatelliteAccessConfigurationWrapper.java
new file mode 100644
index 0000000..694a2be
--- /dev/null
+++ b/satellite_client/src/android/telephony/satellite/wrapper/SatelliteAccessConfigurationWrapper.java
@@ -0,0 +1,142 @@
+/*
+ * Copyright (C) 2024 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.wrapper;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import androidx.annotation.NonNull;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * SatelliteAccessConfigurationWrapper is used to store satellite access configuration
+ * that will be applied to the satellite communication at the corresponding region.
+ *
+ * @hide
+ */
+public class SatelliteAccessConfigurationWrapper implements Parcelable {
+    /**
+     * The list of satellites available at the current location.
+     */
+    @NonNull
+    private List<SatelliteInfoWrapper> mSatelliteInfoList;
+
+    /**
+     * The list of tag IDs associated with the current location
+     */
+    @NonNull
+    private List<Integer> mTagIdList;
+
+    /**
+     * Constructor for {@link SatelliteAccessConfigurationWrapper}.
+     *
+     * @param satelliteInfos The list of {@link SatelliteInfoWrapper} objects representing
+     *                       the satellites accessible with this configuration.
+     * @param tagidList      The list of tag IDs associated with this configuration.
+     */
+    public SatelliteAccessConfigurationWrapper(@NonNull List<SatelliteInfoWrapper> satelliteInfos,
+            @NonNull List<Integer> tagidList) {
+        mSatelliteInfoList = satelliteInfos;
+        mTagIdList = tagidList;
+    }
+
+    public SatelliteAccessConfigurationWrapper(Parcel in) {
+        mSatelliteInfoList = in.createTypedArrayList(SatelliteInfoWrapper.CREATOR);
+        mTagIdList = new ArrayList<>();
+        in.readList(mTagIdList, Integer.class.getClassLoader(), Integer.class);
+    }
+
+    public static final Parcelable.Creator<SatelliteAccessConfigurationWrapper> CREATOR =
+            new Parcelable.Creator<SatelliteAccessConfigurationWrapper>() {
+                @Override
+                public SatelliteAccessConfigurationWrapper createFromParcel(Parcel in) {
+                    return new SatelliteAccessConfigurationWrapper(in);
+                }
+
+                @Override
+                public SatelliteAccessConfigurationWrapper[] newArray(int size) {
+                    return new SatelliteAccessConfigurationWrapper[size];
+                }
+            };
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    /**
+     * @param dest  The Parcel in which the object should be written.
+     * @param flags Additional flags about how the object should be written.
+     *              May be 0 or {@link #PARCELABLE_WRITE_RETURN_VALUE}.
+     */
+    @Override
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        dest.writeTypedList(mSatelliteInfoList);
+        dest.writeList(mTagIdList);
+    }
+
+    /**
+     * Returns a list of {@link SatelliteInfoWrapper} objects representing the satellites
+     * associated with this object.
+     *
+     * @return The list of {@link SatelliteInfoWrapper} objects.
+     */
+    @NonNull
+    public List<SatelliteInfoWrapper> getSatelliteInfos() {
+        return mSatelliteInfoList;
+    }
+
+    /**
+     * Returns a list of tag IDs associated with this object.
+     *
+     * @return The list of tag IDs.
+     */
+    @NonNull
+    public List<Integer> getTagIds() {
+        return mTagIdList;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (!(o instanceof SatelliteAccessConfigurationWrapper that)) return false;
+
+        return mSatelliteInfoList.equals(that.mSatelliteInfoList)
+                && Objects.equals(mTagIdList, that.mTagIdList);
+    }
+
+    @Override
+    public int hashCode() {
+        int result = Objects.hash(mSatelliteInfoList);
+        result = 31 * result + Objects.hashCode(mTagIdList);
+        return result;
+    }
+
+    @Override
+    @NonNull
+    public String toString() {
+        StringBuilder sb = new StringBuilder();
+        sb.append("SatelliteAccessConfigurationWrapper{");
+        sb.append("mSatelliteInfoList=").append(mSatelliteInfoList);
+        sb.append(", mTagIds=").append(mTagIdList);
+        sb.append('}');
+        return sb.toString();
+    }
+}
diff --git a/satellite_client/src/android/telephony/satellite/wrapper/SatelliteCommunicationAllowedStateCallbackWrapper2.java b/satellite_client/src/android/telephony/satellite/wrapper/SatelliteCommunicationAllowedStateCallbackWrapper2.java
index 86785e3..744b09c 100644
--- a/satellite_client/src/android/telephony/satellite/wrapper/SatelliteCommunicationAllowedStateCallbackWrapper2.java
+++ b/satellite_client/src/android/telephony/satellite/wrapper/SatelliteCommunicationAllowedStateCallbackWrapper2.java
@@ -17,7 +17,6 @@
 package android.telephony.satellite.wrapper;
 
 import android.annotation.Nullable;
-import android.telephony.satellite.SatelliteAccessConfiguration;
 
 /** A callback class for monitoring satellite communication allowed state change events. */
 public interface SatelliteCommunicationAllowedStateCallbackWrapper2 {
@@ -34,15 +33,14 @@
     /**
      * Callback method invoked when the satellite access configuration changes
      *
-     * @param satelliteAccessConfiguration The satellite access configuration associated with
-     *                                     the current location. When satellite is not allowed at
-     *                                     the current location,
-     *                                     {@code satelliteAccessConfiguration} will be null.
+     * @param satelliteAccessConfigurationWrapper The satellite access configuration associated with
+     *                                            the current location. When satellite is not
+     *                                            allowed at the current location,
+     *                                            {@code satelliteAccessConfigurationWrapper}
+     *                                            will be null.
      * @hide
      */
     default void onSatelliteAccessConfigurationChanged(
-            @Nullable SatelliteAccessConfiguration satelliteAccessConfiguration) {
-    }
-
-    ;
+            @Nullable SatelliteAccessConfigurationWrapper satelliteAccessConfigurationWrapper) {
+    };
 }
diff --git a/satellite_client/src/android/telephony/satellite/wrapper/SatelliteInfoWrapper.java b/satellite_client/src/android/telephony/satellite/wrapper/SatelliteInfoWrapper.java
new file mode 100644
index 0000000..eb40593
--- /dev/null
+++ b/satellite_client/src/android/telephony/satellite/wrapper/SatelliteInfoWrapper.java
@@ -0,0 +1,197 @@
+/*
+ * Copyright (C) 2024 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.wrapper;
+
+import android.annotation.FlaggedApi;
+import android.annotation.Nullable;
+import android.os.Parcel;
+import android.os.ParcelUuid;
+import android.os.Parcelable;
+
+import androidx.annotation.NonNull;
+
+import com.android.internal.telephony.flags.Flags;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+import java.util.UUID;
+
+/**
+ * SatelliteInfoWrapper stores a satellite's identification, position, and frequency information
+ * facilitating efficient satellite communications.
+ *
+ * @hide
+ */
+public class SatelliteInfoWrapper implements Parcelable {
+    /**
+     * Unique identification number for the satellite.
+     * This ID is used to distinguish between different satellites in the network.
+     */
+    @NonNull
+    private UUID mId;
+
+    /**
+     * Position information of a satellite.
+     * This includes the longitude and altitude of the satellite.
+     */
+    @Nullable
+    private SatellitePositionWrapper mPosition;
+
+    /**
+     * The frequency band list to scan. Bands and earfcns won't overlap.
+     * Bands will be filled only if the whole band is needed.
+     * Maximum length of the vector is 8.
+     */
+    private List<Integer> mBandList;
+
+    /**
+     * EARFCN (E-UTRA Absolute Radio Frequency Channel Number) range list
+     * The supported frequency range list.
+     * Maximum length of the vector is 8.
+     */
+    private final List<EarfcnRangeWrapper> mEarfcnRangeList;
+
+    protected SatelliteInfoWrapper(Parcel in) {
+        ParcelUuid parcelUuid = in.readParcelable(
+                ParcelUuid.class.getClassLoader(), ParcelUuid.class);
+        if (parcelUuid != null) {
+            mId = parcelUuid.getUuid();
+        }
+        mPosition = in.readParcelable(SatellitePositionWrapper.class.getClassLoader(),
+                SatellitePositionWrapper.class);
+        mBandList = new ArrayList<>();
+        in.readList(mBandList, Integer.class.getClassLoader(), Integer.class);
+        mEarfcnRangeList = in.createTypedArrayList(EarfcnRangeWrapper.CREATOR);
+    }
+
+    /**
+     * Constructor for {@link SatelliteInfoWrapper}.
+     *
+     * @param satelliteId       The ID of the satellite.
+     * @param satellitePosition The {@link SatellitePositionWrapper} of the satellite.
+     * @param bandList          The list of frequency bandList supported by the satellite.
+     * @param earfcnRanges      The list of {@link EarfcnRangeWrapper} objects representing the
+     *                          EARFCN ranges supported by the satellite.
+     */
+    public SatelliteInfoWrapper(@NonNull UUID satelliteId,
+            @Nullable SatellitePositionWrapper satellitePosition,
+            @NonNull List<Integer> bandList, @NonNull List<EarfcnRangeWrapper> earfcnRanges) {
+        mId = satelliteId;
+        mPosition = satellitePosition;
+        mBandList = bandList;
+        mEarfcnRangeList = earfcnRanges;
+    }
+
+    public static final Parcelable.Creator<SatelliteInfoWrapper>
+            CREATOR = new Parcelable.Creator<SatelliteInfoWrapper>() {
+        @Override
+        public SatelliteInfoWrapper createFromParcel(Parcel in) {
+            return new SatelliteInfoWrapper(in);
+        }
+
+        @Override
+        public SatelliteInfoWrapper[] newArray(int size) {
+            return new SatelliteInfoWrapper[size];
+        }
+    };
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        dest.writeParcelable(new ParcelUuid(mId), flags);
+        dest.writeParcelable(mPosition, flags);
+        dest.writeList(mBandList);
+        dest.writeTypedList(mEarfcnRangeList);
+    }
+
+    /**
+     * Returns the ID of the satellite.
+     *
+     * @return The satellite ID.
+     */
+    @NonNull
+    public UUID getSatelliteId() {
+        return mId;
+    }
+
+    /**
+     * Returns the position of the satellite.
+     *
+     * @return The {@link SatellitePositionWrapper} of the satellite, or {@code null} if the
+     * position is not available.
+     */
+    @Nullable
+    public SatellitePositionWrapper getSatellitePosition() {
+        return mPosition;
+    }
+
+    /**
+     * Returns the list of frequency bands supported by the satellite.
+     *
+     * @return The list of frequency bands.
+     */
+    @NonNull
+    public List<Integer> getBands() {
+        return mBandList;
+    }
+
+    /**
+     * Returns the list of EARFCN ranges supported by the satellite.
+     *
+     * @return The list of {@link EarfcnRangeWrapper} objects.
+     */
+    @NonNull
+    public List<EarfcnRangeWrapper> getEarfcnRanges() {
+        return mEarfcnRangeList;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (!(o instanceof SatelliteInfoWrapper that)) return false;
+
+        return mId.equals(that.mId)
+                && Objects.equals(mPosition, that.mPosition)
+                && Objects.equals(mBandList, that.mBandList)
+                && mEarfcnRangeList.equals(that.mEarfcnRangeList);
+    }
+
+    @Override
+    public int hashCode() {
+        int result = Objects.hash(mId, mPosition, mEarfcnRangeList);
+        result = 31 * result + Objects.hashCode(mBandList);
+        return result;
+    }
+
+    @Override
+    @NonNull
+    public String toString() {
+        StringBuilder sb = new StringBuilder();
+        sb.append("SatelliteInfoWrapper{");
+        sb.append("mId=").append(mId);
+        sb.append(", mPosition=").append(mPosition);
+        sb.append(", mBandList=").append(mBandList);
+        sb.append(", mEarfcnRangeList=").append(mEarfcnRangeList);
+        sb.append('}');
+        return sb.toString();
+    }
+}
diff --git a/satellite_client/src/android/telephony/satellite/wrapper/SatelliteManagerWrapper.java b/satellite_client/src/android/telephony/satellite/wrapper/SatelliteManagerWrapper.java
index 3b7def8..182cab2 100644
--- a/satellite_client/src/android/telephony/satellite/wrapper/SatelliteManagerWrapper.java
+++ b/satellite_client/src/android/telephony/satellite/wrapper/SatelliteManagerWrapper.java
@@ -36,6 +36,7 @@
 import android.telephony.TelephonyCallback;
 import android.telephony.TelephonyManager;
 import android.telephony.satellite.AntennaPosition;
+import android.telephony.satellite.EarfcnRange;
 import android.telephony.satellite.EnableRequestAttributes;
 import android.telephony.satellite.NtnSignalStrength;
 import android.telephony.satellite.NtnSignalStrengthCallback;
@@ -46,6 +47,7 @@
 import android.telephony.satellite.SatelliteCommunicationAllowedStateCallback;
 import android.telephony.satellite.SatelliteDatagram;
 import android.telephony.satellite.SatelliteDatagramCallback;
+import android.telephony.satellite.SatelliteInfo;
 import android.telephony.satellite.SatelliteManager;
 import android.telephony.satellite.SatelliteModemStateCallback;
 import android.telephony.satellite.SatelliteProvisionStateCallback;
@@ -70,6 +72,7 @@
 import java.util.Map;
 import java.util.Objects;
 import java.util.Set;
+import java.util.UUID;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.Executor;
 import java.util.function.Consumer;
@@ -1924,6 +1927,30 @@
     return result;
   }
 
+  private List<SatelliteInfoWrapper> getSatelliteInfoListWrapper(
+          List<SatelliteInfo> satelliteInfoList) {
+      List<SatelliteInfoWrapper> satelliteInfoWrapperList = new ArrayList<>();
+      for (SatelliteInfo info : satelliteInfoList) {
+          SatellitePositionWrapper satellitePositionWrapperWrapper = null;
+          if (info.getSatellitePosition() != null) {
+              satellitePositionWrapperWrapper = new SatellitePositionWrapper(
+                      info.getSatellitePosition().getLongitudeDegrees(),
+                      info.getSatellitePosition().getAltitudeKm());
+          }
+          List<EarfcnRangeWrapper> earfcnRangeWrapperList = new ArrayList<>();
+          for (EarfcnRange range : info.getEarfcnRanges()) {
+              earfcnRangeWrapperList.add(new EarfcnRangeWrapper(
+                      range.getStartEarfcn(), range.getEndEarfcn()));
+          }
+          SatelliteInfoWrapper satelliteInfoWrapper = new SatelliteInfoWrapper(
+                  info.getSatelliteId(), satellitePositionWrapperWrapper,
+                  info.getBands(), earfcnRangeWrapperList);
+
+          satelliteInfoWrapperList.add(satelliteInfoWrapper);
+      }
+      return satelliteInfoWrapperList;
+  }
+
   /** Registers for the satellite communication allowed state changed. */
   @SatelliteResult
   public int registerForCommunicationAllowedStateChanged2(
@@ -1943,8 +1970,13 @@
 
               @Override
               public void onSatelliteAccessConfigurationChanged(SatelliteAccessConfiguration
-                      satelliteAccessConfiguration) {
-                callback.onSatelliteAccessConfigurationChanged(satelliteAccessConfiguration);
+                      config) {
+                if (config != null) {
+                  callback.onSatelliteAccessConfigurationChanged(
+                          new SatelliteAccessConfigurationWrapper(
+                                  getSatelliteInfoListWrapper(config.getSatelliteInfos()),
+                                  config.getTagIds()));
+                }
               }
             };
     sSatelliteCommunicationAllowedStateCallbackWrapperMap2.put(callback, internalCallback);
@@ -1972,6 +2004,19 @@
   }
 
   /**
+   * Unregisters for the satellite communication allowed state changed. If callback was not
+   * registered before, the request will be ignored.
+   */
+  public void unregisterForCommunicationAllowedStateChanged2(
+          @NonNull SatelliteCommunicationAllowedStateCallbackWrapper2 callback) {
+    SatelliteCommunicationAllowedStateCallback internalCallback =
+            sSatelliteCommunicationAllowedStateCallbackWrapperMap2.remove(callback);
+    if (internalCallback != null) {
+      mSatelliteManager.unregisterForCommunicationAllowedStateChanged(internalCallback);
+    }
+  }
+
+  /**
    * Wrapper API to provide a way to check if the subscription is capable for non-terrestrial
    * networks for the carrier.
    *
diff --git a/satellite_client/src/android/telephony/satellite/wrapper/SatellitePositionWrapper.java b/satellite_client/src/android/telephony/satellite/wrapper/SatellitePositionWrapper.java
new file mode 100644
index 0000000..60b197e
--- /dev/null
+++ b/satellite_client/src/android/telephony/satellite/wrapper/SatellitePositionWrapper.java
@@ -0,0 +1,138 @@
+/*
+ * Copyright (C) 2024 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.wrapper;
+
+import android.annotation.FlaggedApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import androidx.annotation.NonNull;
+
+import com.android.internal.telephony.flags.Flags;
+
+import java.util.Objects;
+
+/**
+ * The position of a satellite in Earth orbit.
+ *
+ * Longitude is the angular distance, measured in degrees, east or west of the prime longitude line
+ * ranging from -180 to 180 degrees
+ * Altitude is the distance from the center of the Earth to the satellite, measured in kilometers
+ *
+ * @hide
+ */
+public class SatellitePositionWrapper implements Parcelable {
+
+    /**
+     * The longitude of the satellite in degrees, ranging from -180 to 180 degrees
+     */
+    private double mLongitudeDegree;
+
+    /**
+     * The distance from the center of the earth to the satellite, measured in kilometers
+     */
+    private double mAltitudeKm;
+
+    /**
+     * Constructor for {@link SatellitePositionWrapper} used to create an instance from a
+     * {@link Parcel}.
+     *
+     * @param in The {@link Parcel} to read the satellite position data from.
+     */
+    public SatellitePositionWrapper(Parcel in) {
+        mLongitudeDegree = in.readDouble();
+        mAltitudeKm = in.readDouble();
+    }
+
+    /**
+     * Constructor for {@link SatellitePositionWrapper}.
+     *
+     * @param longitudeDegree The longitude of the satellite in degrees.
+     * @param altitudeKm      The altitude of the satellite in kilometers.
+     */
+    public SatellitePositionWrapper(double longitudeDegree, double altitudeKm) {
+        mLongitudeDegree = longitudeDegree;
+        mAltitudeKm = altitudeKm;
+    }
+
+    public static final Creator<SatellitePositionWrapper> CREATOR =
+            new Creator<SatellitePositionWrapper>() {
+                @Override
+                public SatellitePositionWrapper createFromParcel(Parcel in) {
+                    return new SatellitePositionWrapper(in);
+                }
+
+                @Override
+                public SatellitePositionWrapper[] newArray(int size) {
+                    return new SatellitePositionWrapper[size];
+                }
+            };
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    /**
+     * @param dest  The Parcel in which the object should be written.
+     * @param flags Additional flags about how the object should be written.
+     *              May be 0 or {@link #PARCELABLE_WRITE_RETURN_VALUE}.
+     */
+    @Override
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        dest.writeDouble(mLongitudeDegree);
+        dest.writeDouble(mAltitudeKm);
+    }
+
+    /**
+     * Returns the longitude of the satellite in degrees, ranging from -180 to 180 degrees.
+     *
+     * @return The longitude of the satellite.
+     */
+    public double getLongitudeDegrees() {
+        return mLongitudeDegree;
+    }
+
+    /**
+     * Returns the altitude of the satellite in kilometers
+     *
+     * @return The altitude of the satellite.
+     */
+    public double getAltitudeKm() {
+        return mAltitudeKm;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (!(o instanceof SatellitePositionWrapper that)) return false;
+
+        return Double.compare(that.mLongitudeDegree, mLongitudeDegree) == 0
+                && Double.compare(that.mAltitudeKm, mAltitudeKm) == 0;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(mLongitudeDegree, mAltitudeKm);
+    }
+
+    @Override
+    @NonNull
+    public String toString() {
+        return "mLongitudeDegree: " + mLongitudeDegree + ", " + "mAltitudeKm: " + mAltitudeKm;
+    }
+}