/* * Copyright 2017 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; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SystemApi; import android.annotation.TestApi; import android.os.Parcel; import android.os.Parcelable; import android.telephony.AccessNetworkConstants.TransportType; import android.telephony.TelephonyManager.NetworkType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Objects; import java.util.stream.Collectors; /** * Description of a mobile network registration info * @hide */ @SystemApi @TestApi public final class NetworkRegistrationInfo implements Parcelable { /** * Network domain * @hide */ @Retention(RetentionPolicy.SOURCE) @IntDef(prefix = "DOMAIN_", value = {DOMAIN_CS, DOMAIN_PS}) public @interface Domain {} /** Circuit switching domain */ public static final int DOMAIN_CS = 1; /** Packet switching domain */ public static final int DOMAIN_PS = 2; /** * Network registration state * @hide */ @Retention(RetentionPolicy.SOURCE) @IntDef(prefix = "REGISTRATION_STATE_", value = {REGISTRATION_STATE_NOT_REGISTERED_OR_SEARCHING, REGISTRATION_STATE_HOME, REGISTRATION_STATE_NOT_REGISTERED_SEARCHING, REGISTRATION_STATE_DENIED, REGISTRATION_STATE_UNKNOWN, REGISTRATION_STATE_ROAMING}) public @interface RegistrationState {} /** Not registered. The device is not currently searching a new operator to register. */ public static final int REGISTRATION_STATE_NOT_REGISTERED_OR_SEARCHING = 0; /** Registered on home network. */ public static final int REGISTRATION_STATE_HOME = 1; /** Not registered. The device is currently searching a new operator to register. */ public static final int REGISTRATION_STATE_NOT_REGISTERED_SEARCHING = 2; /** Registration denied. */ public static final int REGISTRATION_STATE_DENIED = 3; /** Registration state is unknown. */ public static final int REGISTRATION_STATE_UNKNOWN = 4; /** Registered on roaming network. */ public static final int REGISTRATION_STATE_ROAMING = 5; /** @hide */ @Retention(RetentionPolicy.SOURCE) @IntDef(prefix = "NR_STATE_", value = {NR_STATE_NONE, NR_STATE_RESTRICTED, NR_STATE_NOT_RESTRICTED, NR_STATE_CONNECTED}) public @interface NRState {} /** * The device isn't camped on an LTE cell or the LTE cell doesn't support E-UTRA-NR * Dual Connectivity(EN-DC). * @hide */ public static final int NR_STATE_NONE = -1; /** * The device is camped on an LTE cell that supports E-UTRA-NR Dual Connectivity(EN-DC) but * either the use of dual connectivity with NR(DCNR) is restricted or NR is not supported by * the selected PLMN. * @hide */ public static final int NR_STATE_RESTRICTED = 1; /** * The device is camped on an LTE cell that supports E-UTRA-NR Dual Connectivity(EN-DC) and both * the use of dual connectivity with NR(DCNR) is not restricted and NR is supported by the * selected PLMN. * @hide */ public static final int NR_STATE_NOT_RESTRICTED = 2; /** * The device is camped on an LTE cell that supports E-UTRA-NR Dual Connectivity(EN-DC) and * also connected to at least one 5G cell as a secondary serving cell. * @hide */ public static final int NR_STATE_CONNECTED = 3; /** * Supported service type * @hide */ @Retention(RetentionPolicy.SOURCE) @IntDef(prefix = "SERVICE_TYPE_", value = {SERVICE_TYPE_UNKNOWN, SERVICE_TYPE_VOICE, SERVICE_TYPE_DATA, SERVICE_TYPE_SMS, SERVICE_TYPE_VIDEO, SERVICE_TYPE_EMERGENCY}) public @interface ServiceType {} /** Unkown service */ public static final int SERVICE_TYPE_UNKNOWN = 0; /** Voice service */ public static final int SERVICE_TYPE_VOICE = 1; /** Data service */ public static final int SERVICE_TYPE_DATA = 2; /** SMS service */ public static final int SERVICE_TYPE_SMS = 3; /** Video service */ public static final int SERVICE_TYPE_VIDEO = 4; /** Emergency service */ public static final int SERVICE_TYPE_EMERGENCY = 5; @Domain private final int mDomain; @TransportType private final int mTransportType; @RegistrationState private final int mRegistrationState; /** * Save the {@link ServiceState.RoamingType roaming type}. it can be overridden roaming type * from resource overlay or carrier config. */ @ServiceState.RoamingType private int mRoamingType; @NetworkType private int mAccessNetworkTechnology; @NRState private int mNrState; private final int mRejectCause; private final boolean mEmergencyOnly; @ServiceType private final ArrayList mAvailableServices; @Nullable private CellIdentity mCellIdentity; @Nullable private VoiceSpecificRegistrationInfo mVoiceSpecificInfo; @Nullable private DataSpecificRegistrationInfo mDataSpecificInfo; /** * @param domain Network domain. Must be a {@link Domain}. For transport type * {@link AccessNetworkConstants#TRANSPORT_TYPE_WLAN}, this must set to {@link #DOMAIN_PS}. * @param transportType Transport type. * @param registrationState Network registration state. For transport type * {@link AccessNetworkConstants#TRANSPORT_TYPE_WLAN}, only * {@link #REGISTRATION_STATE_HOME} and {@link #REGISTRATION_STATE_NOT_REGISTERED_OR_SEARCHING} * are valid states. * @param accessNetworkTechnology Access network technology.For transport type * {@link AccessNetworkConstants#TRANSPORT_TYPE_WLAN}, set to * {@link TelephonyManager#NETWORK_TYPE_IWLAN}. * @param rejectCause Reason for denial if the registration state is * {@link #REGISTRATION_STATE_DENIED}. Depending on {@code accessNetworkTechnology}, the values * are defined in 3GPP TS 24.008 10.5.3.6 for UMTS, 3GPP TS 24.301 9.9.3.9 for LTE, and 3GPP2 * A.S0001 6.2.2.44 for CDMA. If the reject cause is not supported or unknown, set it to 0. * // TODO: Add IWLAN reject cause reference * @param emergencyOnly True if this registration is for emergency only. * @param availableServices The list of the supported services. * @param cellIdentity The identity representing a unique cell or wifi AP. Set to null if the * information is not available. */ private NetworkRegistrationInfo(@Domain int domain, @TransportType int transportType, @RegistrationState int registrationState, @NetworkType int accessNetworkTechnology, int rejectCause, boolean emergencyOnly, @Nullable @ServiceType List availableServices, @Nullable CellIdentity cellIdentity) { mDomain = domain; mTransportType = transportType; mRegistrationState = registrationState; mRoamingType = (registrationState == REGISTRATION_STATE_ROAMING) ? ServiceState.ROAMING_TYPE_UNKNOWN : ServiceState.ROAMING_TYPE_NOT_ROAMING; mAccessNetworkTechnology = accessNetworkTechnology; mRejectCause = rejectCause; mAvailableServices = (availableServices != null) ? new ArrayList<>(availableServices) : new ArrayList<>(); mCellIdentity = cellIdentity; mEmergencyOnly = emergencyOnly; mNrState = NR_STATE_NONE; } /** * Constructor for voice network registration info. * @hide */ public NetworkRegistrationInfo(int domain, @TransportType int transportType, int registrationState, int accessNetworkTechnology, int rejectCause, boolean emergencyOnly, @Nullable List availableServices, @Nullable CellIdentity cellIdentity, boolean cssSupported, int roamingIndicator, int systemIsInPrl, int defaultRoamingIndicator) { this(domain, transportType, registrationState, accessNetworkTechnology, rejectCause, emergencyOnly, availableServices, cellIdentity); mVoiceSpecificInfo = new VoiceSpecificRegistrationInfo(cssSupported, roamingIndicator, systemIsInPrl, defaultRoamingIndicator); } /** * Constructor for data network registration info. * @hide */ public NetworkRegistrationInfo(int domain, @TransportType int transportType, int registrationState, int accessNetworkTechnology, int rejectCause, boolean emergencyOnly, @Nullable List availableServices, @Nullable CellIdentity cellIdentity, int maxDataCalls, boolean isDcNrRestricted, boolean isNrAvailable, boolean isEndcAvailable, LteVopsSupportInfo lteVopsSupportInfo, boolean isUsingCarrierAggregation) { this(domain, transportType, registrationState, accessNetworkTechnology, rejectCause, emergencyOnly, availableServices, cellIdentity); mDataSpecificInfo = new DataSpecificRegistrationInfo( maxDataCalls, isDcNrRestricted, isNrAvailable, isEndcAvailable, lteVopsSupportInfo, isUsingCarrierAggregation); updateNrState(mDataSpecificInfo); } private NetworkRegistrationInfo(Parcel source) { mDomain = source.readInt(); mTransportType = source.readInt(); mRegistrationState = source.readInt(); mRoamingType = source.readInt(); mAccessNetworkTechnology = source.readInt(); mRejectCause = source.readInt(); mEmergencyOnly = source.readBoolean(); mAvailableServices = new ArrayList<>(); source.readList(mAvailableServices, Integer.class.getClassLoader()); mCellIdentity = source.readParcelable(CellIdentity.class.getClassLoader()); mVoiceSpecificInfo = source.readParcelable( VoiceSpecificRegistrationInfo.class.getClassLoader()); mDataSpecificInfo = source.readParcelable( DataSpecificRegistrationInfo.class.getClassLoader()); mNrState = source.readInt(); } /** * Constructor from another network registration info * * @param nri Another network registration info * @hide */ public NetworkRegistrationInfo(NetworkRegistrationInfo nri) { mDomain = nri.mDomain; mTransportType = nri.mTransportType; mRegistrationState = nri.mRegistrationState; mRoamingType = nri.mRoamingType; mAccessNetworkTechnology = nri.mAccessNetworkTechnology; mRejectCause = nri.mRejectCause; mEmergencyOnly = nri.mEmergencyOnly; mAvailableServices = new ArrayList<>(nri.mAvailableServices); if (nri.mCellIdentity != null) { Parcel p = Parcel.obtain(); nri.mCellIdentity.writeToParcel(p, 0); p.setDataPosition(0); // TODO: Instead of doing this, we should create a formal way for cloning cell identity. // Cell identity is not an immutable object so we have to deep copy it. mCellIdentity = CellIdentity.CREATOR.createFromParcel(p); } if (nri.mVoiceSpecificInfo != null) { mVoiceSpecificInfo = new VoiceSpecificRegistrationInfo(nri.mVoiceSpecificInfo); } if (nri.mDataSpecificInfo != null) { mDataSpecificInfo = new DataSpecificRegistrationInfo(nri.mDataSpecificInfo); } mNrState = nri.mNrState; } /** * @return The transport type. */ public @TransportType int getTransportType() { return mTransportType; } /** * @return The network domain. */ public @Domain int getDomain() { return mDomain; } /** * @return the 5G NR connection state. * @hide */ public @NRState int getNrState() { return mNrState; } /** @hide */ public void setNrState(@NRState int nrState) { mNrState = nrState; } /** * @return The registration state. */ public @RegistrationState int getRegistrationState() { return mRegistrationState; } /** * @return {@code true} if registered on roaming network, {@code false} otherwise. */ public boolean isRoaming() { return mRoamingType != ServiceState.ROAMING_TYPE_NOT_ROAMING; } /** * @hide * @return {@code true} if in service. */ public boolean isInService() { return mRegistrationState == REGISTRATION_STATE_HOME || mRegistrationState == REGISTRATION_STATE_ROAMING; } /** * Set {@link ServiceState.RoamingType roaming type}. This could override * roaming type based on resource overlay or carrier config. * @hide */ public void setRoamingType(@ServiceState.RoamingType int roamingType) { mRoamingType = roamingType; } /** * @return the current network roaming type. */ public @ServiceState.RoamingType int getRoamingType() { return mRoamingType; } /** * @return Whether emergency is enabled. */ public boolean isEmergencyEnabled() { return mEmergencyOnly; } /** * @return List of available service types. */ @NonNull @ServiceType public List getAvailableServices() { return Collections.unmodifiableList(mAvailableServices); } /** * @return The access network technology {@link NetworkType}. */ public @NetworkType int getAccessNetworkTechnology() { return mAccessNetworkTechnology; } /** * override the access network technology {@link NetworkType} e.g, rat ratchet. * @hide */ public void setAccessNetworkTechnology(@NetworkType int tech) { if (tech == TelephonyManager.NETWORK_TYPE_LTE_CA) { // For old device backward compatibility support tech = TelephonyManager.NETWORK_TYPE_LTE; if (mDataSpecificInfo != null) { mDataSpecificInfo.setIsUsingCarrierAggregation(true); } } mAccessNetworkTechnology = tech; } /** * @return Reason for denial if the registration state is {@link #REGISTRATION_STATE_DENIED}. * Depending on {@code accessNetworkTechnology}, the values are defined in 3GPP TS 24.008 * 10.5.3.6 for UMTS, 3GPP TS 24.301 9.9.3.9 for LTE, and 3GPP2 A.S0001 6.2.2.44 for CDMA */ public int getRejectCause() { return mRejectCause; } /** * @return The cell information. */ @Nullable public CellIdentity getCellIdentity() { return mCellIdentity; } /** * @hide */ @Nullable public VoiceSpecificRegistrationInfo getVoiceSpecificInfo() { return mVoiceSpecificInfo; } /** * @return Data registration related info */ @Nullable public DataSpecificRegistrationInfo getDataSpecificInfo() { return mDataSpecificInfo; } @Override public int describeContents() { return 0; } /** * Convert service type to string * * @hide * * @param serviceType The service type * @return The service type in string format */ public static String serviceTypeToString(@ServiceType int serviceType) { switch (serviceType) { case SERVICE_TYPE_VOICE: return "VOICE"; case SERVICE_TYPE_DATA: return "DATA"; case SERVICE_TYPE_SMS: return "SMS"; case SERVICE_TYPE_VIDEO: return "VIDEO"; case SERVICE_TYPE_EMERGENCY: return "EMERGENCY"; } return "Unknown service type " + serviceType; } /** * Convert registration state to string * * @hide * * @param registrationState The registration state * @return The reg state in string */ public static String registrationStateToString(@RegistrationState int registrationState) { switch (registrationState) { case REGISTRATION_STATE_NOT_REGISTERED_OR_SEARCHING: return "NOT_REG_OR_SEARCHING"; case REGISTRATION_STATE_HOME: return "HOME"; case REGISTRATION_STATE_NOT_REGISTERED_SEARCHING: return "NOT_REG_SEARCHING"; case REGISTRATION_STATE_DENIED: return "DENIED"; case REGISTRATION_STATE_UNKNOWN: return "UNKNOWN"; case REGISTRATION_STATE_ROAMING: return "ROAMING"; } return "Unknown reg state " + registrationState; } private static String nrStateToString(@NRState int nrState) { switch (nrState) { case NR_STATE_RESTRICTED: return "RESTRICTED"; case NR_STATE_NOT_RESTRICTED: return "NOT_RESTRICTED"; case NR_STATE_CONNECTED: return "CONNECTED"; default: return "NONE"; } } @Override public String toString() { return new StringBuilder("NetworkRegistrationInfo{") .append(" domain=").append((mDomain == DOMAIN_CS) ? "CS" : "PS") .append(" transportType=").append( AccessNetworkConstants.transportTypeToString(mTransportType)) .append(" registrationState=").append(registrationStateToString(mRegistrationState)) .append(" roamingType=").append(ServiceState.roamingTypeToString(mRoamingType)) .append(" accessNetworkTechnology=") .append(TelephonyManager.getNetworkTypeName(mAccessNetworkTechnology)) .append(" rejectCause=").append(mRejectCause) .append(" emergencyEnabled=").append(mEmergencyOnly) .append(" availableServices=").append("[" + (mAvailableServices != null ? mAvailableServices.stream().map(type -> serviceTypeToString(type)) .collect(Collectors.joining(",")) : null) + "]") .append(" cellIdentity=").append(mCellIdentity) .append(" voiceSpecificInfo=").append(mVoiceSpecificInfo) .append(" dataSpecificInfo=").append(mDataSpecificInfo) .append(" nrState=").append(nrStateToString(mNrState)) .append("}").toString(); } @Override public int hashCode() { return Objects.hash(mDomain, mTransportType, mRegistrationState, mRoamingType, mAccessNetworkTechnology, mRejectCause, mEmergencyOnly, mAvailableServices, mCellIdentity, mVoiceSpecificInfo, mDataSpecificInfo, mNrState); } @Override public boolean equals(Object o) { if (this == o) return true; if (!(o instanceof NetworkRegistrationInfo)) { return false; } NetworkRegistrationInfo other = (NetworkRegistrationInfo) o; return mDomain == other.mDomain && mTransportType == other.mTransportType && mRegistrationState == other.mRegistrationState && mRoamingType == other.mRoamingType && mAccessNetworkTechnology == other.mAccessNetworkTechnology && mRejectCause == other.mRejectCause && mEmergencyOnly == other.mEmergencyOnly && mAvailableServices.equals(other.mAvailableServices) && Objects.equals(mCellIdentity, other.mCellIdentity) && Objects.equals(mVoiceSpecificInfo, other.mVoiceSpecificInfo) && Objects.equals(mDataSpecificInfo, other.mDataSpecificInfo) && mNrState == other.mNrState; } @Override public void writeToParcel(Parcel dest, int flags) { dest.writeInt(mDomain); dest.writeInt(mTransportType); dest.writeInt(mRegistrationState); dest.writeInt(mRoamingType); dest.writeInt(mAccessNetworkTechnology); dest.writeInt(mRejectCause); dest.writeBoolean(mEmergencyOnly); dest.writeList(mAvailableServices); dest.writeParcelable(mCellIdentity, 0); dest.writeParcelable(mVoiceSpecificInfo, 0); dest.writeParcelable(mDataSpecificInfo, 0); dest.writeInt(mNrState); } /** * Use the 5G NR Non-Standalone indicators from the network registration state to update the * NR state. There are 3 indicators in the network registration state: * * 1. if E-UTRA-NR Dual Connectivity (EN-DC) is supported by the primary serving cell. * 2. if NR is supported by the selected PLMN. * 3. if the use of dual connectivity with NR is restricted. * * The network has 5G NR capability if E-UTRA-NR Dual Connectivity is supported by the primary * serving cell. * * The use of NR 5G is not restricted If the network has 5G NR capability and both the use of * DCNR is not restricted and NR is supported by the selected PLMN. Otherwise the use of 5G * NR is restricted. * * @param state data specific registration state contains the 5G NR indicators. */ private void updateNrState(DataSpecificRegistrationInfo state) { mNrState = NR_STATE_NONE; if (state.isEnDcAvailable) { if (!state.isDcNrRestricted && state.isNrAvailable) { mNrState = NR_STATE_NOT_RESTRICTED; } else { mNrState = NR_STATE_RESTRICTED; } } } public static final @NonNull Parcelable.Creator CREATOR = new Parcelable.Creator() { @Override public NetworkRegistrationInfo createFromParcel(Parcel source) { return new NetworkRegistrationInfo(source); } @Override public NetworkRegistrationInfo[] newArray(int size) { return new NetworkRegistrationInfo[size]; } }; /** * @hide */ public NetworkRegistrationInfo sanitizeLocationInfo() { NetworkRegistrationInfo result = copy(); result.mCellIdentity = null; return result; } private NetworkRegistrationInfo copy() { Parcel p = Parcel.obtain(); this.writeToParcel(p, 0); p.setDataPosition(0); NetworkRegistrationInfo result = new NetworkRegistrationInfo(p); p.recycle(); return result; } /** * Provides a convenient way to set the fields of a {@link NetworkRegistrationInfo} when * creating a new instance. * *

The example below shows how you might create a new {@code NetworkRegistrationInfo}: * *


     *
     * NetworkRegistrationInfo nri = new NetworkRegistrationInfo.Builder()
     *     .setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_LTE)
     *     .setRegistrationState(REGISTRATION_STATE_HOME)
     *     .build();
     * 
*/ public static final class Builder{ @Domain private int mDomain; @TransportType private int mTransportType; @RegistrationState private int mRegistrationState; @NetworkType private int mAccessNetworkTechnology; private int mRejectCause; private boolean mEmergencyOnly; @ServiceType private List mAvailableServices; @Nullable private CellIdentity mCellIdentity; /** * Default constructor for Builder. */ public Builder() {} /** * Set the network domain. * * @param domain Network domain. * * @return The same instance of the builder. */ public @NonNull Builder setDomain(@Domain int domain) { mDomain = domain; return this; } /** * Set the transport type. * * @param transportType Transport type. * * @return The same instance of the builder. */ public @NonNull Builder setTransportType(@TransportType int transportType) { mTransportType = transportType; return this; } /** * Set the registration state. * * @param registrationState The registration state. * * @return The same instance of the builder. */ public @NonNull Builder setRegistrationState(@RegistrationState int registrationState) { mRegistrationState = registrationState; return this; } /** * Set tne access network technology. * * @return The same instance of the builder. * * @param accessNetworkTechnology The access network technology */ public @NonNull Builder setAccessNetworkTechnology( @NetworkType int accessNetworkTechnology) { mAccessNetworkTechnology = accessNetworkTechnology; return this; } /** * Set the network reject cause. * * @param rejectCause Reason for denial if the registration state is * {@link #REGISTRATION_STATE_DENIED}.Depending on {@code accessNetworkTechnology}, the * values are defined in 3GPP TS 24.008 10.5.3.6 for UMTS, 3GPP TS 24.301 9.9.3.9 for LTE, * and 3GPP2 A.S0001 6.2.2.44 for CDMA. If the reject cause is not supported or unknown, set * it to 0. * * @return The same instance of the builder. */ public @NonNull Builder setRejectCause(int rejectCause) { mRejectCause = rejectCause; return this; } /** * Set emergency only. * * @param emergencyOnly True if this network registration is for emergency use only. * * @return The same instance of the builder. */ public @NonNull Builder setEmergencyOnly(boolean emergencyOnly) { mEmergencyOnly = emergencyOnly; return this; } /** * Set the available services. * * @param availableServices Available services. * * @return The same instance of the builder. */ public @NonNull Builder setAvailableServices( @NonNull @ServiceType List availableServices) { mAvailableServices = availableServices; return this; } /** * Set the cell identity. * * @param cellIdentity The cell identity. * * @return The same instance of the builder. */ public @NonNull Builder setCellIdentity(@Nullable CellIdentity cellIdentity) { mCellIdentity = cellIdentity; return this; } /** * Build the NetworkRegistrationInfo. * * @return the NetworkRegistrationInfo object. */ public @NonNull NetworkRegistrationInfo build() { return new NetworkRegistrationInfo(mDomain, mTransportType, mRegistrationState, mAccessNetworkTechnology, mRejectCause, mEmergencyOnly, mAvailableServices, mCellIdentity); } } }