Merge 25Q1 (ab/BP1A.250305.020) to AOSP main Bug: 385190204 Merged-In: Ibf5b40a60cf52966cf0927e939f953eae22a9a26 Change-Id: Ia01093d17fafa05fe6ea8721f90457de52dbfc87
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 new file mode 100644 index 0000000..744b09c --- /dev/null +++ b/satellite_client/src/android/telephony/satellite/wrapper/SatelliteCommunicationAllowedStateCallbackWrapper2.java
@@ -0,0 +1,46 @@ +/* + * 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.Nullable; + +/** A callback class for monitoring satellite communication allowed state change events. */ +public interface SatelliteCommunicationAllowedStateCallbackWrapper2 { + /** + * Telephony does not guarantee that whenever there is a change in communication allowed state, + * this API will be called. Telephony does its best to detect the changes and notify its + * listeners accordingly. + * + * @param isAllowed {@code true} means satellite allow state is changed, + * {@code false} satellite allow state is not changed + */ + void onSatelliteCommunicationAllowedStateChanged(boolean isAllowed); + + /** + * Callback method invoked when the satellite access configuration changes + * + * @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 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..bdbb379 --- /dev/null +++ b/satellite_client/src/android/telephony/satellite/wrapper/SatelliteInfoWrapper.java
@@ -0,0 +1,195 @@ +/* + * 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.Nullable; +import android.os.Parcel; +import android.os.ParcelUuid; +import android.os.Parcelable; + +import androidx.annotation.NonNull; + +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 geostationary satellite. + * This includes the longitude and altitude of the satellite. + * If the SatellitePosition is invalid, + * longitudeDegree and altitudeKm will be represented as DOUBLE.NaN. + */ + @NonNull + 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, + @NonNull 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. + */ + @NonNull + 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 e4f38f9..b4c55d1 100644 --- a/satellite_client/src/android/telephony/satellite/wrapper/SatelliteManagerWrapper.java +++ b/satellite_client/src/android/telephony/satellite/wrapper/SatelliteManagerWrapper.java
@@ -26,6 +26,7 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.content.Context; +import android.os.Binder; import android.os.CancellationSignal; import android.os.OutcomeReceiver; import android.telephony.NetworkRegistrationInfo; @@ -35,15 +36,18 @@ 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; import android.telephony.satellite.PointingInfo; +import android.telephony.satellite.SatelliteAccessConfiguration; import android.telephony.satellite.SatelliteCapabilities; import android.telephony.satellite.SatelliteCapabilitiesCallback; 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; @@ -52,6 +56,7 @@ import android.telephony.satellite.SatelliteSubscriberProvisionStatus; import android.telephony.satellite.SatelliteSupportedStateCallback; import android.telephony.satellite.SatelliteTransmissionUpdateCallback; +import android.telephony.satellite.SelectedNbIotSatelliteSubscriptionCallback; import com.android.internal.telephony.flags.Flags; import com.android.telephony.Rlog; @@ -61,6 +66,7 @@ import java.lang.reflect.Method; import java.time.Duration; import java.util.ArrayList; +import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -78,6 +84,8 @@ public class SatelliteManagerWrapper { private static final String TAG = "SatelliteManagerWrapper"; + private static final int VERSION = 1; + private static final ConcurrentHashMap< SatelliteDatagramCallbackWrapper, SatelliteDatagramCallback> sSatelliteDatagramCallbackWrapperMap = new ConcurrentHashMap<>(); @@ -126,6 +134,14 @@ SatelliteCommunicationAllowedStateCallback> sSatelliteCommunicationAllowedStateCallbackWrapperMap = new ConcurrentHashMap<>(); + private static final ConcurrentHashMap<SatelliteCommunicationAllowedStateCallbackWrapper2, + SatelliteCommunicationAllowedStateCallback> + sSatelliteCommunicationAllowedStateCallbackWrapperMap2 = new ConcurrentHashMap<>(); + + private static final ConcurrentHashMap<SelectedNbIotSatelliteSubscriptionCallbackWrapper, + SelectedNbIotSatelliteSubscriptionCallback> + sSelectedNbIotSatelliteSubscriptionCallbackWrapperMap = new ConcurrentHashMap<>(); + private final SatelliteManager mSatelliteManager; private final SubscriptionManager mSubscriptionManager; private final TelephonyManager mTelephonyManager; @@ -174,6 +190,12 @@ * Datagram type indicating that the message to be sent or received is of type SMS. */ public static final int DATAGRAM_TYPE_SMS = 6; + /** + * Datagram type indicating that the message to be sent is an SMS checking + * for pending incoming SMS. + * @hide + */ + public static final int DATAGRAM_TYPE_CHECK_PENDING_INCOMING_SMS = 7; /** @hide */ @IntDef( @@ -185,7 +207,8 @@ DATAGRAM_TYPE_KEEP_ALIVE, DATAGRAM_TYPE_LAST_SOS_MESSAGE_STILL_NEED_HELP, DATAGRAM_TYPE_LAST_SOS_MESSAGE_NO_HELP_NEEDED, - DATAGRAM_TYPE_SMS + DATAGRAM_TYPE_SMS, + DATAGRAM_TYPE_CHECK_PENDING_INCOMING_SMS }) @Retention(RetentionPolicy.SOURCE) public @interface DatagramType {} @@ -539,6 +562,14 @@ } /** + * Returns the current version of the satellite wrapper. Versions start at 1. + * There is no to explicit versioning support before the first version. + */ + public int getVersion() { + return VERSION; + } + + /** * Request to enable or disable the satellite modem and demo mode. If the satellite modem is * enabled, this may also disable the cellular modem, and if the satellite modem is disabled, this * may also re-enable the cellular modem. @@ -549,6 +580,13 @@ boolean isEmergency, @NonNull @CallbackExecutor Executor executor, @SatelliteResult @NonNull Consumer<Integer> resultListener) { + if (mSatelliteManager == null) { + logd("requestEnabled: mSatelliteManager is null"); + executor.execute(() -> Binder.withCleanCallingIdentity(() -> resultListener.accept( + SatelliteManager.SATELLITE_RESULT_REQUEST_NOT_SUPPORTED))); + return; + } + mSatelliteManager.requestEnabled(new EnableRequestAttributes.Builder(enableSatellite) .setDemoMode(enableDemoMode) .setEmergencyMode(isEmergency) @@ -559,6 +597,14 @@ public void requestIsEnabled( @NonNull @CallbackExecutor Executor executor, @NonNull OutcomeReceiver<Boolean, SatelliteExceptionWrapper> callback) { + if (mSatelliteManager == null) { + logd("requestIsEnabled: mSatelliteManager is null"); + executor.execute(() -> Binder.withCleanCallingIdentity(() -> callback.onError( + new SatelliteExceptionWrapper( + SatelliteManager.SATELLITE_RESULT_REQUEST_NOT_SUPPORTED)))); + return; + } + OutcomeReceiver internalCallback = new OutcomeReceiver<Boolean, SatelliteException>() { @Override @@ -578,6 +624,14 @@ public void requestIsDemoModeEnabled( @NonNull @CallbackExecutor Executor executor, @NonNull OutcomeReceiver<Boolean, SatelliteExceptionWrapper> callback) { + if (mSatelliteManager == null) { + logd("requestIsDemoModeEnabled: mSatelliteManager is null"); + executor.execute(() -> Binder.withCleanCallingIdentity(() -> callback.onError( + new SatelliteExceptionWrapper( + SatelliteManager.SATELLITE_RESULT_REQUEST_NOT_SUPPORTED)))); + return; + } + OutcomeReceiver internalCallback = new OutcomeReceiver<Boolean, SatelliteException>() { @Override @@ -597,6 +651,14 @@ public void requestIsEmergencyModeEnabled( @NonNull @CallbackExecutor Executor executor, @NonNull OutcomeReceiver<Boolean, SatelliteExceptionWrapper> callback) { + if (mSatelliteManager == null) { + logd("requestIsEmergencyModeEnabled: mSatelliteManager is null"); + executor.execute(() -> Binder.withCleanCallingIdentity(() -> callback.onError( + new SatelliteExceptionWrapper( + SatelliteManager.SATELLITE_RESULT_REQUEST_NOT_SUPPORTED)))); + return; + } + OutcomeReceiver internalCallback = new OutcomeReceiver<Boolean, SatelliteException>() { @Override @@ -616,6 +678,12 @@ public void requestIsSupported( @NonNull @CallbackExecutor Executor executor, @NonNull OutcomeReceiver<Boolean, SatelliteExceptionWrapper> callback) { + if (mSatelliteManager == null) { + logd("requestIsSupported: mSatelliteManager is null"); + executor.execute(() -> Binder.withCleanCallingIdentity(() -> callback.onResult(false))); + return; + } + OutcomeReceiver internalCallback = new OutcomeReceiver<Boolean, SatelliteException>() { @Override @@ -635,6 +703,14 @@ public void requestCapabilities( @NonNull @CallbackExecutor Executor executor, @NonNull OutcomeReceiver<SatelliteCapabilitiesWrapper, SatelliteExceptionWrapper> callback) { + if (mSatelliteManager == null) { + logd("requestCapabilities: mSatelliteManager is null"); + executor.execute(() -> Binder.withCleanCallingIdentity(() -> callback.onError( + new SatelliteExceptionWrapper( + SatelliteManager.SATELLITE_RESULT_REQUEST_NOT_SUPPORTED)))); + return; + } + OutcomeReceiver internalCallback = new OutcomeReceiver<SatelliteCapabilities, SatelliteException>() { @Override @@ -667,6 +743,12 @@ @NonNull @CallbackExecutor Executor executor, @SatelliteResult @NonNull Consumer<Integer> resultListener, @NonNull SatelliteTransmissionUpdateCallbackWrapper callback) { + if (mSatelliteManager == null) { + logd("startTransmissionUpdates: mSatelliteManager is null"); + executor.execute(() -> Binder.withCleanCallingIdentity(() -> resultListener.accept( + SatelliteManager.SATELLITE_RESULT_REQUEST_NOT_SUPPORTED))); + return; + } SatelliteTransmissionUpdateCallback internalCallback = new SatelliteTransmissionUpdateCallback() { @@ -721,6 +803,12 @@ @NonNull @CallbackExecutor Executor executor, @SatelliteResult @NonNull Consumer<Integer> resultListener, @NonNull SatelliteTransmissionUpdateCallbackWrapper2 callback) { + if (mSatelliteManager == null) { + logd("startTransmissionUpdates2: mSatelliteManager is null"); + executor.execute(() -> Binder.withCleanCallingIdentity(() -> resultListener.accept( + SatelliteManager.SATELLITE_RESULT_REQUEST_NOT_SUPPORTED))); + return; + } SatelliteTransmissionUpdateCallback internalCallback = new SatelliteTransmissionUpdateCallback() { @@ -779,6 +867,13 @@ @NonNull SatelliteTransmissionUpdateCallbackWrapper callback, @NonNull @CallbackExecutor Executor executor, @SatelliteResult @NonNull Consumer<Integer> resultListener) { + if (mSatelliteManager == null) { + logd("stopTransmissionUpdates: mSatelliteManager is null"); + executor.execute(() -> Binder.withCleanCallingIdentity(() -> resultListener.accept( + SatelliteManager.SATELLITE_RESULT_REQUEST_NOT_SUPPORTED))); + return; + } + SatelliteTransmissionUpdateCallback internalCallback = sSatelliteTransmissionUpdateCallbackWrapperMap.remove(callback); if (internalCallback != null) { @@ -797,6 +892,13 @@ @NonNull SatelliteTransmissionUpdateCallbackWrapper2 callback, @NonNull @CallbackExecutor Executor executor, @SatelliteResult @NonNull Consumer<Integer> resultListener) { + if (mSatelliteManager == null) { + logd("stopTransmissionUpdates2: mSatelliteManager is null"); + executor.execute(() -> Binder.withCleanCallingIdentity(() -> resultListener.accept( + SatelliteManager.SATELLITE_RESULT_REQUEST_NOT_SUPPORTED))); + return; + } + SatelliteTransmissionUpdateCallback internalCallback = sSatelliteTransmissionUpdateCallbackWrapperMap2.remove(callback); if (internalCallback != null) { @@ -815,6 +917,13 @@ @Nullable CancellationSignal cancellationSignal, @NonNull @CallbackExecutor Executor executor, @SatelliteResult @NonNull Consumer<Integer> resultListener) { + if (mSatelliteManager == null) { + logd("provisionService: mSatelliteManager is null"); + executor.execute(() -> Binder.withCleanCallingIdentity(() -> resultListener.accept( + SatelliteManager.SATELLITE_RESULT_REQUEST_NOT_SUPPORTED))); + return; + } + mSatelliteManager.provisionService( token, provisionData, cancellationSignal, executor, resultListener); } @@ -829,6 +938,13 @@ @NonNull String token, @NonNull @CallbackExecutor Executor executor, @SatelliteResult @NonNull Consumer<Integer> resultListener) { + if (mSatelliteManager == null) { + logd("deprovisionService: mSatelliteManager is null"); + executor.execute(() -> Binder.withCleanCallingIdentity(() -> resultListener.accept( + SatelliteManager.SATELLITE_RESULT_REQUEST_NOT_SUPPORTED))); + return; + } + mSatelliteManager.deprovisionService(token, executor, resultListener); } @@ -837,6 +953,11 @@ public int registerForProvisionStateChanged( @NonNull @CallbackExecutor Executor executor, @NonNull SatelliteProvisionStateCallbackWrapper callback) { + if (mSatelliteManager == null) { + logd("registerForProvisionStateChanged: mSatelliteManager is null"); + return SatelliteManagerWrapper.SATELLITE_RESULT_REQUEST_NOT_SUPPORTED; + } + SatelliteProvisionStateCallback internalCallback = new SatelliteProvisionStateCallback() { @Override @@ -863,6 +984,11 @@ */ public void unregisterForProvisionStateChanged( @NonNull SatelliteProvisionStateCallbackWrapper callback) { + if (mSatelliteManager == null){ + logd("unregisterForProvisionStateChanged: mSatelliteManager is null"); + return; + } + SatelliteProvisionStateCallback internalCallback = sSatelliteProvisionStateCallbackWrapperMap.remove(callback); if (internalCallback != null) { @@ -874,6 +1000,14 @@ public void requestIsProvisioned( @NonNull @CallbackExecutor Executor executor, @NonNull OutcomeReceiver<Boolean, SatelliteExceptionWrapper> callback) { + if (mSatelliteManager == null) { + logd("requestIsProvisioned: mSatelliteManager is null"); + executor.execute(() -> Binder.withCleanCallingIdentity(() -> callback.onError( + new SatelliteExceptionWrapper( + SatelliteManager.SATELLITE_RESULT_REQUEST_NOT_SUPPORTED)))); + return; + } + OutcomeReceiver internalCallback = new OutcomeReceiver<Boolean, SatelliteException>() { @Override @@ -894,6 +1028,11 @@ public int registerForModemStateChanged( @NonNull @CallbackExecutor Executor executor, @NonNull SatelliteModemStateCallbackWrapper callback) { + if (mSatelliteManager == null) { + logd("registerForModemStateChanged: mSatelliteManager is null"); + return SatelliteManagerWrapper.SATELLITE_RESULT_REQUEST_NOT_SUPPORTED; + } + SatelliteModemStateCallback internalCallback = new SatelliteModemStateCallback() { public void onSatelliteModemStateChanged(@SatelliteModemState int state) { @@ -912,6 +1051,11 @@ public int registerForModemStateChanged( @NonNull @CallbackExecutor Executor executor, @NonNull SatelliteModemStateCallbackWrapper2 callback) { + if (mSatelliteManager == null) { + logd("registerForModemStateChanged: mSatelliteManager is null"); + return SatelliteManagerWrapper.SATELLITE_RESULT_REQUEST_NOT_SUPPORTED; + } + SatelliteModemStateCallback internalCallback = new SatelliteModemStateCallback() { public void onSatelliteModemStateChanged(@SatelliteModemState int state) { @@ -925,6 +1069,10 @@ public void onRegistrationFailure(int causeCode) { callback.onRegistrationFailure(causeCode); } + + public void onTerrestrialNetworkAvailableChanged(boolean isAvailable) { + callback.onTerrestrialNetworkAvailableChanged(isAvailable); + } }; sSatelliteModemStateCallbackWrapperMap2.put(callback, internalCallback); @@ -939,6 +1087,11 @@ */ public void unregisterForModemStateChanged( @NonNull SatelliteModemStateCallbackWrapper callback) { + if (mSatelliteManager == null) { + logd("unregisterForModemStateChanged: mSatelliteManager is null"); + return; + } + SatelliteModemStateCallback internalCallback = sSatelliteModemStateCallbackWrapperMap.remove( callback); if (internalCallback != null) { @@ -952,6 +1105,11 @@ */ public void unregisterForModemStateChanged( @NonNull SatelliteModemStateCallbackWrapper2 callback) { + if (mSatelliteManager == null) { + logd("unregisterForModemStateChanged: mSatelliteManager is null"); + return; + } + SatelliteModemStateCallback internalCallback = sSatelliteModemStateCallbackWrapperMap2.remove( callback); if (internalCallback != null) { @@ -964,6 +1122,11 @@ public int registerForIncomingDatagram( @NonNull @CallbackExecutor Executor executor, @NonNull SatelliteDatagramCallbackWrapper callback) { + if (mSatelliteManager == null) { + logd("registerForIncomingDatagram: mSatelliteManager is null"); + return SatelliteManagerWrapper.SATELLITE_RESULT_REQUEST_NOT_SUPPORTED; + } + SatelliteDatagramCallback internalCallback = new SatelliteDatagramCallback() { @Override @@ -989,6 +1152,11 @@ * before, the request will be ignored. */ public void unregisterForIncomingDatagram(@NonNull SatelliteDatagramCallbackWrapper callback) { + if (mSatelliteManager == null) { + logd("unregisterForIncomingDatagram: mSatelliteManager is null"); + return; + } + SatelliteDatagramCallback internalCallback = sSatelliteDatagramCallbackWrapperMap.remove(callback); if (internalCallback != null) { @@ -1029,6 +1197,12 @@ mListenerWrapper2.onCarrierRoamingNtnEligibleStateChanged(eligible); } } + + @Override + public void onCarrierRoamingNtnAvailableServicesChanged( + @NetworkRegistrationInfo.ServiceType int[] availableServices) { + logd("onCarrierRoamingNtnAvailableServicesChanged"); + } } /** Register for carrier roaming non-terrestrial network mode changes. */ @@ -1082,6 +1256,13 @@ public void pollPendingDatagrams( @NonNull @CallbackExecutor Executor executor, @SatelliteResult @NonNull Consumer<Integer> resultListener) { + if (mSatelliteManager == null) { + logd("pollPendingDatagrams: mSatelliteManager is null"); + executor.execute(() -> Binder.withCleanCallingIdentity(() -> resultListener.accept( + SatelliteManager.SATELLITE_RESULT_REQUEST_NOT_SUPPORTED))); + return; + } + mSatelliteManager.pollPendingDatagrams(executor, resultListener); } @@ -1098,6 +1279,13 @@ boolean needFullScreenPointingUI, @NonNull @CallbackExecutor Executor executor, @SatelliteResult @NonNull Consumer<Integer> resultListener) { + if (mSatelliteManager == null) { + logd("sendDatagram: mSatelliteManager is null"); + executor.execute(() -> Binder.withCleanCallingIdentity(() -> resultListener.accept( + SatelliteManager.SATELLITE_RESULT_REQUEST_NOT_SUPPORTED))); + return; + } + SatelliteDatagram datagramInternal = new SatelliteDatagram(datagram.getSatelliteDatagram()); mSatelliteManager.sendDatagram( datagramType, datagramInternal, needFullScreenPointingUI, executor, resultListener); @@ -1107,6 +1295,14 @@ public void requestIsCommunicationAllowedForCurrentLocation( @NonNull @CallbackExecutor Executor executor, @NonNull OutcomeReceiver<Boolean, SatelliteExceptionWrapper> callback) { + if (mSatelliteManager == null) { + logd("requestIsCommunicationAllowedForCurrentLocation: mSatelliteManager is null"); + executor.execute(() -> Binder.withCleanCallingIdentity(() -> callback.onError( + new SatelliteExceptionWrapper( + SatelliteManager.SATELLITE_RESULT_REQUEST_NOT_SUPPORTED)))); + return; + } + OutcomeReceiver internalCallback = new OutcomeReceiver<Boolean, SatelliteException>() { @Override @@ -1123,6 +1319,37 @@ executor, internalCallback); } + /** Request to get satellite access configuration for the current location. */ + public void requestSatelliteAccessConfigurationForCurrentLocation( + @NonNull @CallbackExecutor Executor executor, + @NonNull OutcomeReceiver<SatelliteAccessConfigurationWrapper, SatelliteExceptionWrapper> callback) { + if (mSatelliteManager == null) { + logd("requestSatelliteAccessConfigurationForCurrentLocation: mSatelliteManager is null"); + executor.execute(() -> Binder.withCleanCallingIdentity(() -> callback.onError( + new SatelliteExceptionWrapper( + SatelliteManager.SATELLITE_RESULT_REQUEST_NOT_SUPPORTED)))); + return; + } + + OutcomeReceiver internalCallback = + new OutcomeReceiver<SatelliteAccessConfiguration, SatelliteException>() { + @Override + public void onResult(SatelliteAccessConfiguration result) { + callback.onResult(new SatelliteAccessConfigurationWrapper( + getSatelliteInfoListWrapper(result.getSatelliteInfos()), + result.getTagIds())); + } + + @Override + public void onError(SatelliteException exception) { + callback.onError(new SatelliteExceptionWrapper(exception.getErrorCode())); + } + }; + + mSatelliteManager.requestSatelliteAccessConfigurationForCurrentLocation(executor, + internalCallback); + } + /** * Request to get the duration in seconds after which the satellite will be visible. This will be * {@link Duration#ZERO} if the satellite is currently visible. @@ -1130,6 +1357,14 @@ public void requestTimeForNextSatelliteVisibility( @NonNull @CallbackExecutor Executor executor, @NonNull OutcomeReceiver<Duration, SatelliteExceptionWrapper> callback) { + if (mSatelliteManager == null) { + logd("requestTimeForNextSatelliteVisibility: mSatelliteManager is null"); + executor.execute(() -> Binder.withCleanCallingIdentity(() -> callback.onError( + new SatelliteExceptionWrapper( + SatelliteManager.SATELLITE_RESULT_REQUEST_NOT_SUPPORTED)))); + return; + } + OutcomeReceiver internalCallback = new OutcomeReceiver<Duration, SatelliteException>() { @Override @@ -1146,9 +1381,111 @@ } /** + * Request to get the name to display for Satellite as a {@link String}. + */ + public void requestSatelliteDisplayName( + @NonNull @CallbackExecutor Executor executor, + @NonNull OutcomeReceiver<CharSequence, SatelliteExceptionWrapper> callback) { + if (mSatelliteManager == null) { + logd("requestSatelliteDisplayName: mSatelliteManager is null"); + executor.execute(() -> Binder.withCleanCallingIdentity(() -> callback.onError( + new SatelliteExceptionWrapper( + SatelliteManager.SATELLITE_RESULT_REQUEST_NOT_SUPPORTED)))); + return; + } + + OutcomeReceiver internalCallback = + new OutcomeReceiver<CharSequence, SatelliteException>() { + @Override + public void onResult(CharSequence result) { + callback.onResult(result); + } + + @Override + public void onError(SatelliteException exception) { + callback.onError(new SatelliteExceptionWrapper(exception.getErrorCode())); + } + }; + mSatelliteManager.requestSatelliteDisplayName(executor, internalCallback); + } + + /** + * Request to get the currently selected satellite subscription id as an {@link Integer}. + */ + public void requestSelectedNbIotSatelliteSubscriptionId( + @NonNull @CallbackExecutor Executor executor, + @NonNull OutcomeReceiver<Integer, SatelliteExceptionWrapper> callback) { + if (mSatelliteManager == null) { + logd("requestSelectedNbIotSatelliteSubscriptionId: mSatelliteManager is null"); + executor.execute(() -> Binder.withCleanCallingIdentity(() -> callback.onError( + new SatelliteExceptionWrapper( + SatelliteManager.SATELLITE_RESULT_REQUEST_NOT_SUPPORTED)))); + return; + } + + OutcomeReceiver internalCallback = + new OutcomeReceiver<Integer, SatelliteException>() { + @Override + public void onResult(Integer result) { + callback.onResult(result); + } + + @Override + public void onError(SatelliteException exception) { + callback.onError(new SatelliteExceptionWrapper(exception.getErrorCode())); + } + }; + mSatelliteManager.requestSelectedNbIotSatelliteSubscriptionId(executor, internalCallback); + } + + /** + * Wrapper API to register for selected satellite subscription changed event from the satellite + * service. + * + * @param executor The executor on which the callback will be called. + * @param callback The callback to handle the selected satellite subscription changed event. + */ + @SatelliteResult public int registerForSelectedNbIotSatelliteSubscriptionChanged( + @NonNull @CallbackExecutor Executor executor, + @NonNull SelectedNbIotSatelliteSubscriptionCallbackWrapper callback) { + SelectedNbIotSatelliteSubscriptionCallback internalCallback = + selectedSubId -> callback.onSelectedNbIotSatelliteSubscriptionChanged( + selectedSubId); + sSelectedNbIotSatelliteSubscriptionCallbackWrapperMap.put(callback, internalCallback); + return mSatelliteManager.registerForSelectedNbIotSatelliteSubscriptionChanged(executor, + internalCallback); + } + + /** + * Wrapper API to unregisters for selected satellite subscription changed event from the + * satellite service. If callback was not registered before, the request will be ignored. + * + * @param callback The callback that was passed to {@link + * #registerForSelectedNbIotSatelliteSubscriptionChanged(Executor, + * SelectedNbIotSatelliteSubscriptionCallbackWrapper)}. + */ + public void unregisterForSelectedNbIotSatelliteSubscriptionChanged( + @NonNull SelectedNbIotSatelliteSubscriptionCallbackWrapper callback) { + SelectedNbIotSatelliteSubscriptionCallback internalCallback = + sSelectedNbIotSatelliteSubscriptionCallbackWrapperMap.remove(callback); + if (internalCallback != null) { + mSatelliteManager.unregisterForSelectedNbIotSatelliteSubscriptionChanged( + internalCallback); + } else { + logd("unregisterForSelectedNbIotSatelliteSubscriptionChanged: internalCallback is" + + " null"); + } + } + + /** * Inform whether the device is aligned with the satellite for demo mode. */ public void setDeviceAlignedWithSatellite(boolean isAligned) { + if (mSatelliteManager == null) { + logd("setDeviceAlignedWithSatellite: mSatelliteManager is null"); + return; + } + mSatelliteManager.setDeviceAlignedWithSatellite(isAligned); } @@ -1177,6 +1514,14 @@ public void requestNtnSignalStrength( @NonNull @CallbackExecutor Executor executor, @NonNull OutcomeReceiver<NtnSignalStrengthWrapper, SatelliteExceptionWrapper> callback) { + if (mSatelliteManager == null) { + logd("requestNtnSignalStrength: mSatelliteManager is null"); + executor.execute(() -> Binder.withCleanCallingIdentity(() -> callback.onError( + new SatelliteExceptionWrapper( + SatelliteManager.SATELLITE_RESULT_REQUEST_NOT_SUPPORTED)))); + return; + } + OutcomeReceiver internalCallback = new OutcomeReceiver<NtnSignalStrength, SatelliteException>() { @Override @@ -1197,6 +1542,11 @@ public void registerForNtnSignalStrengthChanged( @NonNull @CallbackExecutor Executor executor, @NonNull NtnSignalStrengthCallbackWrapper callback) { + if (mSatelliteManager == null){ + logd("registerForNtnSignalStrengthChanged: mSatelliteManager is null"); + return; + } + NtnSignalStrengthCallback internalCallback = new NtnSignalStrengthCallback() { @Override @@ -1216,6 +1566,11 @@ @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG) public void unregisterForNtnSignalStrengthChanged( @NonNull NtnSignalStrengthCallbackWrapper callback) { + if (mSatelliteManager == null){ + logd("unregisterForNtnSignalStrengthChanged: mSatelliteManager is null"); + return; + } + NtnSignalStrengthCallback internalCallback = sNtnSignalStrengthCallbackWrapperMap.remove(callback); if (internalCallback != null) { @@ -1260,6 +1615,11 @@ public int registerForCapabilitiesChanged( @NonNull @CallbackExecutor Executor executor, @NonNull SatelliteCapabilitiesCallbackWrapper callback) { + if (mSatelliteManager == null) { + logd("requestForCapabilitiesChanged: mSatelliteManager is null"); + return SatelliteManager.SATELLITE_RESULT_REQUEST_NOT_SUPPORTED; + } + SatelliteCapabilitiesCallback internalCallback = capabilities -> callback.onSatelliteCapabilitiesChanged( new SatelliteCapabilitiesWrapper( @@ -1281,6 +1641,11 @@ @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG) public void unregisterForCapabilitiesChanged( @NonNull SatelliteCapabilitiesCallbackWrapper callback) { + if (mSatelliteManager == null) { + logd("unregisterForCapabilitiesChanged: mSatelliteManager is null"); + return; + } + SatelliteCapabilitiesCallback internalCallback = sSatelliteCapabilitiesCallbackWrapperMap.remove(callback); if (internalCallback != null) { @@ -1394,6 +1759,13 @@ public void requestAttachEnabledForCarrier(int subId, boolean enableSatellite, @NonNull @CallbackExecutor Executor executor, @SatelliteResult @NonNull Consumer<Integer> resultListener) { + if (mSatelliteManager == null) { + logd("requestAttachEnabledForCarrier: mSatelliteManager is null"); + executor.execute(() -> Binder.withCleanCallingIdentity(() -> resultListener.accept( + SatelliteManager.SATELLITE_RESULT_REQUEST_NOT_SUPPORTED))); + return; + } + mSatelliteManager.requestAttachEnabledForCarrier(subId, enableSatellite, executor, resultListener); } @@ -1419,6 +1791,14 @@ public void requestIsAttachEnabledForCarrier(int subId, @NonNull @CallbackExecutor Executor executor, @NonNull OutcomeReceiver<Boolean, SatelliteExceptionWrapper> callback) { + if (mSatelliteManager == null) { + logd("requestIsAttachEnabledForCarrier: mSatelliteManager is null"); + executor.execute(() -> Binder.withCleanCallingIdentity(() -> callback.onError( + new SatelliteExceptionWrapper( + SatelliteManager.SATELLITE_RESULT_REQUEST_NOT_SUPPORTED)))); + return; + } + OutcomeReceiver internalCallback = new OutcomeReceiver<Boolean, SatelliteException>() { @Override @@ -1451,6 +1831,13 @@ @SatelliteCommunicationRestrictionReason int reason, @NonNull @CallbackExecutor Executor executor, @SatelliteResult @NonNull Consumer<Integer> resultListener) { + if (mSatelliteManager == null) { + logd("addAttachRestrictionForCarrier: mSatelliteManager is null"); + executor.execute(() -> Binder.withCleanCallingIdentity(() -> resultListener.accept( + SatelliteManager.SATELLITE_RESULT_REQUEST_NOT_SUPPORTED))); + return; + } + mSatelliteManager.addAttachRestrictionForCarrier(subId, reason, executor, resultListener); } @@ -1471,6 +1858,13 @@ @SatelliteCommunicationRestrictionReason int reason, @NonNull @CallbackExecutor Executor executor, @SatelliteResult @NonNull Consumer<Integer> resultListener) { + if (mSatelliteManager == null) { + logd("removeAttachRestrictionForCarrier: mSatelliteManager is null"); + executor.execute(() -> Binder.withCleanCallingIdentity(() -> resultListener.accept( + SatelliteManager.SATELLITE_RESULT_REQUEST_NOT_SUPPORTED))); + return; + } + mSatelliteManager.removeAttachRestrictionForCarrier(subId, reason, executor, resultListener); } @@ -1487,6 +1881,11 @@ */ @SatelliteCommunicationRestrictionReason @NonNull public Set<Integer> getAttachRestrictionReasonsForCarrier(int subId) { + if (mSatelliteManager == null) { + logd("getAttachRestrictionReasonsForCarrier: mSatelliteManager is null"); + return Collections.emptySet(); + } + return mSatelliteManager.getAttachRestrictionReasonsForCarrier(subId); } @@ -1499,6 +1898,11 @@ * be returned. */ @NonNull public List<String> getSatellitePlmnsForCarrier(int subId) { + if (mSatelliteManager == null) { + logd("getSatellitePlmnsForCarrier: mSatelliteManager is null"); + return new ArrayList<>(); + } + return mSatelliteManager.getSatellitePlmnsForCarrier(subId); } @@ -1507,6 +1911,11 @@ public int registerForSupportedStateChanged( @NonNull @CallbackExecutor Executor executor, @NonNull SatelliteSupportedStateCallbackWrapper callback) { + if (mSatelliteManager == null) { + logd("registerForSupportedStateChanged: mSatelliteManager is null"); + return SatelliteManagerWrapper.SATELLITE_RESULT_REQUEST_NOT_SUPPORTED; + } + SatelliteSupportedStateCallback internalCallback = new SatelliteSupportedStateCallback() { @Override @@ -1525,6 +1934,14 @@ @NonNull @CallbackExecutor Executor executor, @NonNull OutcomeReceiver<SatelliteSessionStatsWrapper, SatelliteExceptionWrapper> callback) { + if (mSatelliteManager == null) { + logd("requestSessionStats: mSatelliteManager is null"); + executor.execute(() -> Binder.withCleanCallingIdentity(() -> callback.onError( + new SatelliteExceptionWrapper( + SatelliteManager.SATELLITE_RESULT_REQUEST_NOT_SUPPORTED)))); + return; + } + OutcomeReceiver internalCallback = new OutcomeReceiver<SatelliteSessionStats, SatelliteException>() { @Override @@ -1552,12 +1969,72 @@ mSatelliteManager.requestSessionStats(executor, internalCallback); } + /** Request to get the {@link SatelliteSessionStatsWrapper2} of the satellite service. */ + public void requestSessionStats2(@NonNull @CallbackExecutor Executor executor, + @NonNull OutcomeReceiver<SatelliteSessionStatsWrapper2, + SatelliteExceptionWrapper> callback) { + logd("requestSessionStats2 called"); + if (mSatelliteManager == null) { + executor.execute(() -> Binder.withCleanCallingIdentity(() -> callback.onError( + new SatelliteExceptionWrapper( + SatelliteManager.SATELLITE_RESULT_REQUEST_NOT_SUPPORTED)))); + return; + } + OutcomeReceiver internalCallback = + new OutcomeReceiver<SatelliteSessionStats, SatelliteException>() { + @Override + public void onResult(SatelliteSessionStats result) { + logd("requestSessionStats2 onResult received"); + Map<Integer, SatelliteSessionStats> satelliteSessionStats = + result.getSatelliteSessionStats(); + Map<Integer, SatelliteSessionStatsWrapper2> sessionStatsMap = new HashMap<>(); + for (Map.Entry<Integer, SatelliteSessionStats> entry : + satelliteSessionStats.entrySet()) { + sessionStatsMap.put(entry.getKey(), + buildSatelliteSessionStatsWrapper2(entry.getValue())); + } + SatelliteSessionStatsWrapper2 sessionStatsWrapper2 = + new SatelliteSessionStatsWrapper2(); + sessionStatsWrapper2.setSatelliteSessionStats(sessionStatsMap); + logd("requestSessionStats2 completed sessionStatsWrapper2 = " +sessionStatsWrapper2); + callback.onResult(sessionStatsWrapper2); + } + + @Override + public void onError(SatelliteException exception) { + callback.onError(new SatelliteExceptionWrapper(exception.getErrorCode())); + } + }; + mSatelliteManager.requestSessionStats(executor, internalCallback); + } + + private SatelliteSessionStatsWrapper2 buildSatelliteSessionStatsWrapper2( + SatelliteSessionStats value) { + SatelliteSessionStatsWrapper2 data = new SatelliteSessionStatsWrapper2(); + data.updateLatencyOfAllSuccessfulUserMessages(value.getLatencyOfAllSuccessfulUserMessages()); + data.setMaxLatency(value.getMaxLatency()); + data.setLastMessageLatency(value.getLastMessageLatency()); + data.setCountOfSuccessfulUserMessages(value.getCountOfSuccessfulUserMessages()); + data.setCountOfUnsuccessfulUserMessages(value.getCountOfUnsuccessfulUserMessages()); + data.setCountOfTimedOutUserMessagesWaitingForAck( + value.getCountOfTimedOutUserMessagesWaitingForAck()); + data.setCountOfTimedOutUserMessagesWaitingForConnection( + value.getCountOfTimedOutUserMessagesWaitingForConnection()); + data.setCountOfUserMessagesInQueueToBeSent(value.getCountOfUserMessagesInQueueToBeSent()); + return data; + } + /** * Unregisters for the satellite supported state changed. If callback was not registered before, * the request will be ignored. */ public void unregisterForSupportedStateChanged( @NonNull SatelliteSupportedStateCallbackWrapper callback) { + if (mSatelliteManager == null) { + logd("unregisterForSupportedStateChanged: mSatelliteManager is null"); + return; + } + SatelliteSupportedStateCallback internalCallback = sSatelliteSupportedStateCallbackWrapperMap.remove(callback); if (internalCallback != null) { @@ -1570,6 +2047,11 @@ public int registerForCommunicationAllowedStateChanged( @NonNull @CallbackExecutor Executor executor, @NonNull SatelliteCommunicationAllowedStateCallbackWrapper callback) { + if (mSatelliteManager == null) { + logd("requestForCommunicationAllowedStateChanged: mSatelliteManager is null"); + return SatelliteManagerWrapper.SATELLITE_RESULT_REQUEST_NOT_SUPPORTED; + } + SatelliteCommunicationAllowedStateCallback internalCallback = new SatelliteCommunicationAllowedStateCallback() { @Override @@ -1583,12 +2065,76 @@ return result; } + @NonNull + private List<SatelliteInfoWrapper> getSatelliteInfoListWrapper(@NonNull + List<SatelliteInfo> satelliteInfoList) { + List<SatelliteInfoWrapper> satelliteInfoWrapperList = new ArrayList<>(); + + for (SatelliteInfo info : satelliteInfoList) { + SatellitePositionWrapper satellitePositionWrapper = 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(), satellitePositionWrapper, + info.getBands(), earfcnRangeWrapperList); + + satelliteInfoWrapperList.add(satelliteInfoWrapper); + } + return satelliteInfoWrapperList; + } + + /** Registers for the satellite communication allowed state changed. */ + @SatelliteResult + public int registerForCommunicationAllowedStateChanged2( + @NonNull @CallbackExecutor Executor executor, + @NonNull SatelliteCommunicationAllowedStateCallbackWrapper2 callback) { + if (mSatelliteManager == null) { + logd("registerForCommunicationAllowedStateChanged2: mSatelliteManager is null"); + return SatelliteManagerWrapper.SATELLITE_RESULT_REQUEST_NOT_SUPPORTED; + } + + SatelliteCommunicationAllowedStateCallback internalCallback = + new SatelliteCommunicationAllowedStateCallback() { + @Override + public void onSatelliteCommunicationAllowedStateChanged(boolean supported) { + callback.onSatelliteCommunicationAllowedStateChanged(supported); + } + + @Override + public void onSatelliteAccessConfigurationChanged(SatelliteAccessConfiguration + config) { + if (config != null) { + callback.onSatelliteAccessConfigurationChanged( + new SatelliteAccessConfigurationWrapper( + getSatelliteInfoListWrapper(config.getSatelliteInfos()), + config.getTagIds())); + } + } + }; + sSatelliteCommunicationAllowedStateCallbackWrapperMap2.put(callback, internalCallback); + int result = mSatelliteManager.registerForCommunicationAllowedStateChanged(executor, + internalCallback); + return result; + } + /** * Unregisters for the satellite communication allowed state changed. If callback was not * registered before, the request will be ignored. */ public void unregisterForCommunicationAllowedStateChanged( @NonNull SatelliteCommunicationAllowedStateCallbackWrapper callback) { + if (mSatelliteManager == null) { + logd("unregisterForCommunicationAllowedStateChanged: mSatelliteManager is null"); + return; + } + SatelliteCommunicationAllowedStateCallback internalCallback = sSatelliteCommunicationAllowedStateCallbackWrapperMap.remove(callback); if (internalCallback != null) { @@ -1597,6 +2143,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. * @@ -1636,6 +2195,14 @@ @NonNull @CallbackExecutor Executor executor, @NonNull OutcomeReceiver<List<SatelliteSubscriberProvisionStatusWrapper>, SatelliteExceptionWrapper> callback) { + if (mSatelliteManager == null) { + logd("requestSatelliteSubscriberProvisionStatus: mSatelliteManager is null"); + executor.execute(() -> Binder.withCleanCallingIdentity(() -> callback.onError( + new SatelliteExceptionWrapper( + SatelliteManager.SATELLITE_RESULT_REQUEST_NOT_SUPPORTED)))); + return; + } + Objects.requireNonNull(executor); Objects.requireNonNull(callback); @@ -1665,6 +2232,14 @@ public void provisionSatellite(@NonNull List<SatelliteSubscriberInfoWrapper> list, @NonNull @CallbackExecutor Executor executor, @NonNull OutcomeReceiver<Boolean, SatelliteExceptionWrapper> callback) { + if (mSatelliteManager == null) { + logd("provisionSatellite: mSatelliteManager is null"); + executor.execute(() -> Binder.withCleanCallingIdentity(() -> callback.onError( + new SatelliteExceptionWrapper( + SatelliteManager.SATELLITE_RESULT_REQUEST_NOT_SUPPORTED)))); + return; + } + OutcomeReceiver internalCallback = new OutcomeReceiver<Boolean, SatelliteException>() { @Override @@ -1693,7 +2268,7 @@ for (SatelliteSubscriberProvisionStatus status : input) { SatelliteSubscriberInfo info = status.getSatelliteSubscriberInfo(); output.add(new SatelliteSubscriberProvisionStatusWrapper.Builder() - .setProvisionStatus(status.getProvisionStatus()) + .setProvisionStatus(status.isProvisioned()) .setSatelliteSubscriberInfo( new SatelliteSubscriberInfoWrapper.Builder() .setSubscriberId(info.getSubscriberId()) @@ -1707,6 +2282,11 @@ } public boolean isSatelliteSubscriberIdSupported() { + if (mSatelliteManager == null) { + logd("isSatelliteSubscriberIdSupported: mSatelliteManager is null"); + return false; + } + try { final String methodName = "requestSatelliteSubscriberProvisionStatus"; Method method = mSatelliteManager.getClass().getMethod(methodName, Executor.class, @@ -1717,6 +2297,63 @@ } } + /** + * Deliver the list of deprovisioned satellite subscriber ids. + * + * @param list List of deprovisioned SatelliteSubscriberInfo. + * @param executor The executor on which the callback will be called. + * @param callback The callback object to which the result will be delivered. + */ + @FlaggedApi(Flags.FLAG_CARRIER_ROAMING_NB_IOT_NTN) + public void deprovisionSatellite(@NonNull List<SatelliteSubscriberInfoWrapper> list, + @NonNull @CallbackExecutor Executor executor, + @NonNull OutcomeReceiver<Boolean, SatelliteExceptionWrapper> callback) { + if (mSatelliteManager == null) { + logd("deprovisionSatellite: mSatelliteManager is null"); + executor.execute(() -> Binder.withCleanCallingIdentity(() -> callback.onError( + new SatelliteExceptionWrapper( + SatelliteManager.SATELLITE_RESULT_REQUEST_NOT_SUPPORTED)))); + return; + } + + OutcomeReceiver internalCallback = + new OutcomeReceiver<Boolean, SatelliteException>() { + @Override + public void onResult(Boolean result) { + callback.onResult(result); + } + + @Override + public void onError(SatelliteException exception) { + callback.onError(new SatelliteExceptionWrapper(exception.getErrorCode())); + } + }; + mSatelliteManager.deprovisionSatellite(list.stream() + .map(info -> new SatelliteSubscriberInfo.Builder() + .setSubscriberId(info.getSubscriberId()) + .setCarrierId(info.getCarrierId()).setNiddApn(info.getNiddApn()) + .setSubId(info.getSubId()).setSubscriberIdType(info.getSubscriberIdType()) + .build()) + .collect(Collectors.toList()), executor, internalCallback); + } + + /** + * Inform whether application supports NTN SMS in satellite mode. + * + * This method is used by default messaging application to inform framework whether it supports + * NTN SMS or not. + * + * @param ntnSmsSupported {@code true} If application supports NTN SMS, else {@code false}. + */ + public void setNtnSmsSupported(boolean ntnSmsSupported) { + if (mSatelliteManager == null) { + logd("setNtnSmsSupported: mSatelliteManager is null"); + return; + } + + mSatelliteManager.setNtnSmsSupported(ntnSmsSupported); + } + @Nullable private ServiceState getServiceStateForSubscriptionId(int subId) { if (!mSubscriptionManager.isValidSubscriptionId(subId)) {
diff --git a/satellite_client/src/android/telephony/satellite/wrapper/SatelliteModemStateCallbackWrapper2.java b/satellite_client/src/android/telephony/satellite/wrapper/SatelliteModemStateCallbackWrapper2.java index 054167b..ea01f8b 100644 --- a/satellite_client/src/android/telephony/satellite/wrapper/SatelliteModemStateCallbackWrapper2.java +++ b/satellite_client/src/android/telephony/satellite/wrapper/SatelliteModemStateCallbackWrapper2.java
@@ -40,4 +40,11 @@ * For LTE (EMM), cause codes are TS 24.301 Sec 9.9.3.9 */ default void onRegistrationFailure(int causeCode) {}; + + /** + * Indicates that the background search for terrestrial network is finished with result + * + * @param isAvailable True means there's terrestrial network and false means there's not. + */ + default void onTerrestrialNetworkAvailableChanged(boolean isAvailable) {}; }
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; + } +}
diff --git a/satellite_client/src/android/telephony/satellite/wrapper/SatelliteSessionStatsWrapper2.java b/satellite_client/src/android/telephony/satellite/wrapper/SatelliteSessionStatsWrapper2.java new file mode 100644 index 0000000..6a4a862 --- /dev/null +++ b/satellite_client/src/android/telephony/satellite/wrapper/SatelliteSessionStatsWrapper2.java
@@ -0,0 +1,462 @@ +/* + * 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.NonNull; +import android.os.Parcel; +import android.os.Parcelable; +import android.telephony.satellite.SatelliteManager; +import android.util.Log; + +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; + +/** + * SatelliteSessionStatsWrapper2 is used to represent the usage stats of the satellite service. + */ +public class SatelliteSessionStatsWrapper2 implements Parcelable { + + private static final int VERSION = 2; + private int mCountOfSuccessfulUserMessages; + private int mCountOfUnsuccessfulUserMessages; + private int mCountOfTimedOutUserMessagesWaitingForConnection; + private int mCountOfTimedOutUserMessagesWaitingForAck; + private int mCountOfUserMessagesInQueueToBeSent; + private long mLatencyOfSuccessfulUserMessages; + + private Map<Integer, SatelliteSessionStatsWrapper2> datagramStats; + private long mMaxLatency; + private long mLastMessageLatency; + + + public SatelliteSessionStatsWrapper2() { + this.datagramStats = new HashMap<>(); + } + + + /** + * SatelliteSessionStatsWrapper2 constructor + * + * @param builder Builder to create SatelliteSessionStatsWrapper2 object/ + */ + public SatelliteSessionStatsWrapper2(@NonNull Builder builder) { + mCountOfSuccessfulUserMessages = builder.mCountOfSuccessfulUserMessages; + mCountOfUnsuccessfulUserMessages = builder.mCountOfUnsuccessfulUserMessages; + mCountOfTimedOutUserMessagesWaitingForConnection = + builder.mCountOfTimedOutUserMessagesWaitingForConnection; + mCountOfTimedOutUserMessagesWaitingForAck = + builder.mCountOfTimedOutUserMessagesWaitingForAck; + mCountOfUserMessagesInQueueToBeSent = builder.mCountOfUserMessagesInQueueToBeSent; + mLatencyOfSuccessfulUserMessages = builder.mLatencyOfSuccessfulUserMessages; + } + + private SatelliteSessionStatsWrapper2(Parcel in) { + readFromParcel(in); + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(@NonNull Parcel out, int flags) { + out.writeInt(mCountOfSuccessfulUserMessages); + out.writeInt(mCountOfUnsuccessfulUserMessages); + out.writeInt(mCountOfTimedOutUserMessagesWaitingForConnection); + out.writeInt(mCountOfTimedOutUserMessagesWaitingForAck); + out.writeInt(mCountOfUserMessagesInQueueToBeSent); + out.writeLong(mLatencyOfSuccessfulUserMessages); + out.writeLong(mMaxLatency); + out.writeLong(mLastMessageLatency); + + if (datagramStats != null && !datagramStats.isEmpty()) { + out.writeInt(datagramStats.size()); + for (Map.Entry<Integer, SatelliteSessionStatsWrapper2> entry : + datagramStats.entrySet()) { + out.writeInt(entry.getKey()); + out.writeParcelable(entry.getValue(), flags); + } + } else { + out.writeInt(0); + } + } + + @NonNull + public static final Creator<SatelliteSessionStatsWrapper2> CREATOR = new Creator<>() { + + @Override + public SatelliteSessionStatsWrapper2 createFromParcel(Parcel in) { + return new SatelliteSessionStatsWrapper2(in); + } + + @Override + public SatelliteSessionStatsWrapper2[] newArray(int size) { + return new SatelliteSessionStatsWrapper2[size]; + } + }; + + @Override + @NonNull + public String toString() { + StringBuilder sb = new StringBuilder(); + if (datagramStats != null) { + sb.append(" ====== SatelliteSessionStatsWrapper2 Info ============="); + for (Map.Entry<Integer, SatelliteSessionStatsWrapper2> entry : + datagramStats.entrySet()) { + Integer key = entry.getKey(); + SatelliteSessionStatsWrapper2 value = entry.getValue(); + sb.append("\n"); + sb.append("Key:"); + sb.append(key); + sb.append(", SatelliteSessionStatsWrapper2:["); + value.getPrintableCounters(sb); + sb.append(","); + sb.append(" LatencyOfSuccessfulUserMessages:"); + sb.append(value.mLatencyOfSuccessfulUserMessages); + sb.append(","); + sb.append(" mMaxLatency:"); + sb.append(value.mMaxLatency); + sb.append(","); + sb.append(" mLastMessageLatency:"); + sb.append(value.mLastMessageLatency); + sb.append(","); + sb.append(" VERSION:"); + sb.append(value.VERSION); + sb.append("]"); + sb.append("\n"); + } + sb.append(" ============== ================== ==============="); + sb.append("\n"); + sb.append("\n"); + } else { + sb.append("\n"); + getPrintableCounters(sb); + } + sb.append("\n"); + return sb.toString(); + } + + private void getPrintableCounters(StringBuilder sb) { + sb.append("countOfSuccessfulUserMessages:"); + sb.append(mCountOfSuccessfulUserMessages); + sb.append(","); + + sb.append("countOfUnsuccessfulUserMessages:"); + sb.append(mCountOfUnsuccessfulUserMessages); + sb.append(","); + + sb.append("countOfTimedOutUserMessagesWaitingForConnection:"); + sb.append(mCountOfTimedOutUserMessagesWaitingForConnection); + sb.append(","); + + sb.append("countOfTimedOutUserMessagesWaitingForAck:"); + sb.append(mCountOfTimedOutUserMessagesWaitingForAck); + sb.append(","); + + sb.append("countOfUserMessagesInQueueToBeSent:"); + sb.append(mCountOfUserMessagesInQueueToBeSent); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + SatelliteSessionStatsWrapper2 that = (SatelliteSessionStatsWrapper2) o; + return mCountOfSuccessfulUserMessages == that.mCountOfSuccessfulUserMessages + && mLatencyOfSuccessfulUserMessages == that.mLatencyOfSuccessfulUserMessages + && mCountOfUnsuccessfulUserMessages == that.mCountOfUnsuccessfulUserMessages + && mCountOfTimedOutUserMessagesWaitingForConnection + == that.mCountOfTimedOutUserMessagesWaitingForConnection + && mCountOfTimedOutUserMessagesWaitingForAck + == that.mCountOfTimedOutUserMessagesWaitingForAck + && mCountOfUserMessagesInQueueToBeSent == that.mCountOfUserMessagesInQueueToBeSent; + } + + @Override + public int hashCode() { + return Objects.hash(mCountOfSuccessfulUserMessages, mLatencyOfSuccessfulUserMessages, + mCountOfUnsuccessfulUserMessages, mCountOfTimedOutUserMessagesWaitingForConnection, + mCountOfTimedOutUserMessagesWaitingForAck, mCountOfUserMessagesInQueueToBeSent); + } + + public int getCountOfSuccessfulUserMessages() { + return mCountOfSuccessfulUserMessages; + } + + public void incrementSuccessfulUserMessageCount() { + mCountOfSuccessfulUserMessages++; + } + + public int getCountOfUnsuccessfulUserMessages() { + return mCountOfUnsuccessfulUserMessages; + } + + public void incrementUnsuccessfulUserMessageCount() { + mCountOfUnsuccessfulUserMessages++; + } + + public int getCountOfTimedOutUserMessagesWaitingForConnection() { + return mCountOfTimedOutUserMessagesWaitingForConnection; + } + + public void incrementTimedOutUserMessagesWaitingForConnection() { + mCountOfTimedOutUserMessagesWaitingForConnection++; + } + + public int getCountOfTimedOutUserMessagesWaitingForAck() { + return mCountOfTimedOutUserMessagesWaitingForAck; + } + + public void incrementTimedOutUserMessagesWaitingForAck() { + mCountOfTimedOutUserMessagesWaitingForAck++; + } + + public int getCountOfUserMessagesInQueueToBeSent() { + return mCountOfUserMessagesInQueueToBeSent; + } + + public long getLatencyOfAllSuccessfulUserMessages() { + return mLatencyOfSuccessfulUserMessages; + } + + public void updateLatencyOfAllSuccessfulUserMessages(long messageLatency) { + mLatencyOfSuccessfulUserMessages += messageLatency; + } + + public void recordSuccessfulOutgoingDatagramStats( + @SatelliteManager.DatagramType int datagramType, long latency) { + try { + datagramStats.putIfAbsent(datagramType, new Builder().build()); + SatelliteSessionStatsWrapper2 data = datagramStats.get(datagramType); + data.incrementSuccessfulUserMessageCount(); + if (data.mMaxLatency < latency) { + data.mMaxLatency = latency; + } + data.mLastMessageLatency = latency; + data.updateLatencyOfAllSuccessfulUserMessages(latency); + } catch (Exception e) { + Log.e("SatelliteSessionStatsWrapper2", + "Error while recordSuccessfulOutgoingDatagramStats: " + e.getMessage()); + } + } + + public int getCountOfSuccessfulOutgoingDatagram( + @SatelliteManager.DatagramType int datagramType) { + SatelliteSessionStatsWrapper2 data = datagramStats.getOrDefault(datagramType, + new SatelliteSessionStatsWrapper2()); + return data.getCountOfSuccessfulUserMessages(); + } + + public long getMaxLatency() { + return this.mMaxLatency; + } + + public void setMaxLatency(long latency) { + this.mMaxLatency = latency; + } + + public Long getLatencyOfAllSuccessfulUserMessages( + @SatelliteManager.DatagramType int datagramType) { + SatelliteSessionStatsWrapper2 data = datagramStats.getOrDefault(datagramType, + new SatelliteSessionStatsWrapper2()); + return data.getLatencyOfAllSuccessfulUserMessages(); + } + + public long getLastMessageLatency() { + return this.mLastMessageLatency; + } + + public void setLastMessageLatency(long latency) { + this.mLastMessageLatency = latency; + } + + public void addCountOfUnsuccessfulUserMessages(@SatelliteManager.DatagramType int datagramType, + @SatelliteManager.SatelliteResult int resultCode) { + try { + datagramStats.putIfAbsent(datagramType, new Builder().build()); + SatelliteSessionStatsWrapper2 data = datagramStats.get(datagramType); + data.incrementUnsuccessfulUserMessageCount(); + if (resultCode == SatelliteManager.SATELLITE_RESULT_NOT_REACHABLE) { + data.incrementTimedOutUserMessagesWaitingForConnection(); + } else if (resultCode == SatelliteManager.SATELLITE_RESULT_MODEM_TIMEOUT) { + data.incrementTimedOutUserMessagesWaitingForAck(); + } + } catch (Exception e) { + Log.e("SatelliteSessionStatsWrapper2", + "Error while addCountOfUnsuccessfulUserMessages: " + e.getMessage()); + } + } + + public int getCountOfUnsuccessfulUserMessages(@SatelliteManager.DatagramType int datagramType) { + SatelliteSessionStatsWrapper2 data = datagramStats.get(datagramType); + return data.getCountOfUnsuccessfulUserMessages(); + } + + public int getCountOfTimedOutUserMessagesWaitingForConnection( + @SatelliteManager.DatagramType int datagramType) { + SatelliteSessionStatsWrapper2 data = datagramStats.get(datagramType); + return data.getCountOfTimedOutUserMessagesWaitingForConnection(); + } + + public int getCountOfTimedOutUserMessagesWaitingForAck( + @SatelliteManager.DatagramType int datagramType) { + SatelliteSessionStatsWrapper2 data = datagramStats.get(datagramType); + return data.getCountOfTimedOutUserMessagesWaitingForAck(); + } + + public int getCountOfUserMessagesInQueueToBeSent( + @SatelliteManager.DatagramType int datagramType) { + SatelliteSessionStatsWrapper2 data = datagramStats.get(datagramType); + return data.getCountOfUserMessagesInQueueToBeSent(); + } + + public int getVersion() { + return VERSION; + } + + public void clear() { + datagramStats.clear(); + } + + @NonNull + public Map<Integer, SatelliteSessionStatsWrapper2> getSatelliteSessionStats() { + return datagramStats; + } + + public void setSatelliteSessionStats(Map<Integer, SatelliteSessionStatsWrapper2> sessionStats) { + this.datagramStats = sessionStats; + } + + public void setCountOfSuccessfulUserMessages(int count) { + mCountOfSuccessfulUserMessages = count; + } + + public void setCountOfUnsuccessfulUserMessages(int count) { + mCountOfUnsuccessfulUserMessages = count; + } + + public void setCountOfTimedOutUserMessagesWaitingForConnection(int count) { + mCountOfTimedOutUserMessagesWaitingForConnection = count; + } + + + public void setCountOfTimedOutUserMessagesWaitingForAck(int count) { + mCountOfTimedOutUserMessagesWaitingForAck = count; + } + + + public void setCountOfUserMessagesInQueueToBeSent(int count) { + mCountOfUserMessagesInQueueToBeSent = count; + } + + private void readFromParcel(Parcel in) { + mCountOfSuccessfulUserMessages = in.readInt(); + mCountOfUnsuccessfulUserMessages = in.readInt(); + mCountOfTimedOutUserMessagesWaitingForConnection = in.readInt(); + mCountOfTimedOutUserMessagesWaitingForAck = in.readInt(); + mCountOfUserMessagesInQueueToBeSent = in.readInt(); + mLatencyOfSuccessfulUserMessages = in.readLong(); + mMaxLatency = in.readLong(); + mLastMessageLatency = in.readLong(); + + int size = in.readInt(); + datagramStats = new HashMap<>(); + for (int i = 0; i < size; i++) { + Integer key = in.readInt(); + SatelliteSessionStatsWrapper2 value = in.readParcelable( + SatelliteSessionStatsWrapper2.class.getClassLoader()); + datagramStats.put(key, value); + } + } + + /** + * A builder class to create {@link SatelliteSessionStatsWrapper2} data object. + */ + public static final class Builder { + private int mCountOfSuccessfulUserMessages; + private int mCountOfUnsuccessfulUserMessages; + private int mCountOfTimedOutUserMessagesWaitingForConnection; + private int mCountOfTimedOutUserMessagesWaitingForAck; + private int mCountOfUserMessagesInQueueToBeSent; + private long mLatencyOfSuccessfulUserMessages; + + /** + * Sets countOfSuccessfulUserMessages value of {@link SatelliteSessionStatsWrapper2} + * and then returns the Builder class. + */ + @NonNull + public Builder setCountOfSuccessfulUserMessages(int count) { + mCountOfSuccessfulUserMessages = count; + return this; + } + + /** + * Sets countOfUnsuccessfulUserMessages value of {@link SatelliteSessionStatsWrapper2} + * and then returns the Builder class. + */ + @NonNull + public Builder setCountOfUnsuccessfulUserMessages(int count) { + mCountOfUnsuccessfulUserMessages = count; + return this; + } + + /** + * Sets countOfTimedOutUserMessagesWaitingForConnection value of + * {@link SatelliteSessionStatsWrapper2} and then returns the Builder class. + */ + @NonNull + public Builder setCountOfTimedOutUserMessagesWaitingForConnection(int count) { + mCountOfTimedOutUserMessagesWaitingForConnection = count; + return this; + } + + /** + * Sets countOfTimedOutUserMessagesWaitingForAck value of + * {@link SatelliteSessionStatsWrapper2} + * and then returns the Builder class. + */ + @NonNull + public Builder setCountOfTimedOutUserMessagesWaitingForAck(int count) { + mCountOfTimedOutUserMessagesWaitingForAck = count; + return this; + } + + /** + * Sets countOfUserMessagesInQueueToBeSent value of {@link SatelliteSessionStatsWrapper2} + * and then returns the Builder class. + */ + @NonNull + public Builder setCountOfUserMessagesInQueueToBeSent(int count) { + mCountOfUserMessagesInQueueToBeSent = count; + return this; + } + + @NonNull + public Builder setLatencyOfSuccessfulUserMessages(long latency) { + mLatencyOfSuccessfulUserMessages = latency; + return this; + } + + /** Returns SatelliteSessionStatsWrapper2 object. */ + @NonNull + public SatelliteSessionStatsWrapper2 build() { + return new SatelliteSessionStatsWrapper2(this); + } + } +} \ No newline at end of file
diff --git a/satellite_client/src/android/telephony/satellite/wrapper/SelectedNbIotSatelliteSubscriptionCallbackWrapper.java b/satellite_client/src/android/telephony/satellite/wrapper/SelectedNbIotSatelliteSubscriptionCallbackWrapper.java new file mode 100644 index 0000000..b716de5 --- /dev/null +++ b/satellite_client/src/android/telephony/satellite/wrapper/SelectedNbIotSatelliteSubscriptionCallbackWrapper.java
@@ -0,0 +1,29 @@ +/* + * 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; + +/** + * A callback class for selected satellite subscription changed events. + */ +public interface SelectedNbIotSatelliteSubscriptionCallbackWrapper { + /** + * Called when selected satellite subscription has changed. + * + * @param selectedSubId The new satellite subscription id. + */ + void onSelectedNbIotSatelliteSubscriptionChanged(int selectedSubId); +} \ No newline at end of file