362 lines
11 KiB
Java
362 lines
11 KiB
Java
/*
|
|
* 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.CallSuper;
|
|
import android.annotation.NonNull;
|
|
import android.annotation.Nullable;
|
|
import android.annotation.SystemApi;
|
|
import android.os.Parcel;
|
|
import android.os.Parcelable;
|
|
import android.text.TextUtils;
|
|
|
|
import com.android.telephony.Rlog;
|
|
|
|
import java.util.Objects;
|
|
import java.util.UUID;
|
|
|
|
/**
|
|
* CellIdentity represents the identity of a unique cell. This is the base class for
|
|
* CellIdentityXxx which represents cell identity for specific network access technology.
|
|
*/
|
|
public abstract class CellIdentity implements Parcelable {
|
|
|
|
/** @hide */
|
|
public static final int INVALID_CHANNEL_NUMBER = Integer.MAX_VALUE;
|
|
|
|
/**
|
|
* parameters for validation
|
|
* @hide
|
|
*/
|
|
public static final int MCC_LENGTH = 3;
|
|
|
|
/** @hide */
|
|
public static final int MNC_MIN_LENGTH = 2;
|
|
/** @hide */
|
|
public static final int MNC_MAX_LENGTH = 3;
|
|
|
|
// Log tag
|
|
/** @hide */
|
|
protected final String mTag;
|
|
// Cell identity type
|
|
/** @hide */
|
|
protected final int mType;
|
|
// 3-digit Mobile Country Code in string format. Null for CDMA cell identity.
|
|
/** @hide */
|
|
protected final String mMccStr;
|
|
// 2 or 3-digit Mobile Network Code in string format. Null for CDMA cell identity.
|
|
/** @hide */
|
|
protected final String mMncStr;
|
|
|
|
// long alpha Operator Name String or Enhanced Operator Name String
|
|
/** @hide */
|
|
protected String mAlphaLong;
|
|
// short alpha Operator Name String or Enhanced Operator Name String
|
|
/** @hide */
|
|
protected String mAlphaShort;
|
|
|
|
// Cell Global, 3GPP TS 23.003
|
|
/** @hide */
|
|
protected String mGlobalCellId;
|
|
|
|
|
|
/** @hide */
|
|
protected CellIdentity(@Nullable String tag, int type, @Nullable String mcc,
|
|
@Nullable String mnc, @Nullable String alphal, @Nullable String alphas) {
|
|
mTag = tag;
|
|
mType = type;
|
|
|
|
// Only allow INT_MAX if unknown string mcc/mnc
|
|
if (mcc == null || isMcc(mcc)) {
|
|
mMccStr = mcc;
|
|
} else if (mcc.isEmpty() || mcc.equals(String.valueOf(Integer.MAX_VALUE))) {
|
|
// If the mccStr is empty or unknown, set it as null.
|
|
mMccStr = null;
|
|
} else {
|
|
// TODO: b/69384059 Should throw IllegalArgumentException for the invalid MCC format
|
|
// after the bug got fixed.
|
|
mMccStr = null;
|
|
log("invalid MCC format: " + mcc);
|
|
}
|
|
|
|
if (mnc == null || isMnc(mnc)) {
|
|
mMncStr = mnc;
|
|
} else if (mnc.isEmpty() || mnc.equals(String.valueOf(Integer.MAX_VALUE))) {
|
|
// If the mncStr is empty or unknown, set it as null.
|
|
mMncStr = null;
|
|
} else {
|
|
// TODO: b/69384059 Should throw IllegalArgumentException for the invalid MNC format
|
|
// after the bug got fixed.
|
|
mMncStr = null;
|
|
log("invalid MNC format: " + mnc);
|
|
}
|
|
|
|
if ((mMccStr != null && mMncStr == null) || (mMccStr == null && mMncStr != null)) {
|
|
AnomalyReporter.reportAnomaly(
|
|
UUID.fromString("e257ae06-ac0a-44c0-ba63-823b9f07b3e4"),
|
|
"CellIdentity Missing Half of PLMN ID");
|
|
}
|
|
|
|
mAlphaLong = alphal;
|
|
mAlphaShort = alphas;
|
|
}
|
|
|
|
/** Implement the Parcelable interface */
|
|
@Override
|
|
public int describeContents() {
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* @hide
|
|
* @return The type of the cell identity
|
|
*/
|
|
public @CellInfo.Type int getType() {
|
|
return mType;
|
|
}
|
|
|
|
/**
|
|
* @return MCC or null for CDMA
|
|
* @hide
|
|
*/
|
|
public String getMccString() {
|
|
return mMccStr;
|
|
}
|
|
|
|
/**
|
|
* @return MNC or null for CDMA
|
|
* @hide
|
|
*/
|
|
public String getMncString() {
|
|
return mMncStr;
|
|
}
|
|
|
|
/**
|
|
* Returns the channel number of the cell identity.
|
|
*
|
|
* @hide
|
|
* @return The channel number, or {@link #INVALID_CHANNEL_NUMBER} if not implemented
|
|
*/
|
|
public int getChannelNumber() {
|
|
return INVALID_CHANNEL_NUMBER;
|
|
}
|
|
|
|
/**
|
|
* @return The long alpha tag associated with the current scan result (may be the operator
|
|
* name string or extended operator name string). May be null if unknown.
|
|
*/
|
|
@Nullable
|
|
public CharSequence getOperatorAlphaLong() {
|
|
return mAlphaLong;
|
|
}
|
|
|
|
/**
|
|
* @hide
|
|
*/
|
|
public void setOperatorAlphaLong(String alphaLong) {
|
|
mAlphaLong = alphaLong;
|
|
}
|
|
|
|
/**
|
|
* @return The short alpha tag associated with the current scan result (may be the operator
|
|
* name string or extended operator name string). May be null if unknown.
|
|
*/
|
|
@Nullable
|
|
public CharSequence getOperatorAlphaShort() {
|
|
return mAlphaShort;
|
|
}
|
|
|
|
/**
|
|
* @hide
|
|
*/
|
|
public void setOperatorAlphaShort(String alphaShort) {
|
|
mAlphaShort = alphaShort;
|
|
}
|
|
|
|
/**
|
|
* @return Global Cell ID
|
|
* @hide
|
|
*/
|
|
@Nullable
|
|
public String getGlobalCellId() {
|
|
return mGlobalCellId;
|
|
}
|
|
|
|
/**
|
|
* @param ci a CellIdentity to compare to the current CellIdentity.
|
|
* @return true if ci has the same technology and Global Cell ID; false, otherwise.
|
|
* @hide
|
|
*/
|
|
public boolean isSameCell(@Nullable CellIdentity ci) {
|
|
if (ci == null) return false;
|
|
if (this.getClass() != ci.getClass()) return false;
|
|
return TextUtils.equals(this.getGlobalCellId(), ci.getGlobalCellId());
|
|
}
|
|
|
|
/** @hide */
|
|
public @Nullable String getPlmn() {
|
|
if (mMccStr == null || mMncStr == null) return null;
|
|
return mMccStr + mMncStr;
|
|
}
|
|
|
|
/** @hide */
|
|
protected abstract void updateGlobalCellId();
|
|
|
|
/**
|
|
* @return a CellLocation object for this CellIdentity
|
|
* @hide
|
|
*/
|
|
@SystemApi
|
|
public abstract @NonNull CellLocation asCellLocation();
|
|
|
|
/**
|
|
* Create and a return a new instance of CellIdentity with location-identifying information
|
|
* removed.
|
|
*
|
|
* @hide
|
|
*/
|
|
@SystemApi
|
|
public abstract @NonNull CellIdentity sanitizeLocationInfo();
|
|
|
|
@Override
|
|
public boolean equals(Object other) {
|
|
if (!(other instanceof CellIdentity)) {
|
|
return false;
|
|
}
|
|
|
|
CellIdentity o = (CellIdentity) other;
|
|
return mType == o.mType
|
|
&& TextUtils.equals(mMccStr, o.mMccStr)
|
|
&& TextUtils.equals(mMncStr, o.mMncStr)
|
|
&& TextUtils.equals(mAlphaLong, o.mAlphaLong)
|
|
&& TextUtils.equals(mAlphaShort, o.mAlphaShort);
|
|
}
|
|
|
|
@Override
|
|
public int hashCode() {
|
|
return Objects.hash(mAlphaLong, mAlphaShort, mMccStr, mMncStr, mType);
|
|
}
|
|
|
|
/**
|
|
* Used by child classes for parceling.
|
|
*
|
|
* @hide
|
|
*/
|
|
@CallSuper
|
|
public void writeToParcel(Parcel dest, int type) {
|
|
dest.writeInt(type);
|
|
dest.writeString(mMccStr);
|
|
dest.writeString(mMncStr);
|
|
dest.writeString(mAlphaLong);
|
|
dest.writeString(mAlphaShort);
|
|
}
|
|
|
|
/** Used by phone interface manager to verify if a given string is valid MccMnc
|
|
* @hide
|
|
*/
|
|
public static boolean isValidPlmn(@NonNull String plmn) {
|
|
if (plmn.length() < MCC_LENGTH + MNC_MIN_LENGTH
|
|
|| plmn.length() > MCC_LENGTH + MNC_MAX_LENGTH) {
|
|
return false;
|
|
}
|
|
return (isMcc(plmn.substring(0, MCC_LENGTH)) && isMnc(plmn.substring(MCC_LENGTH)));
|
|
}
|
|
|
|
/**
|
|
* Construct from Parcel
|
|
* @hide
|
|
*/
|
|
protected CellIdentity(String tag, int type, Parcel source) {
|
|
this(tag, type, source.readString(), source.readString(),
|
|
source.readString(), source.readString());
|
|
}
|
|
|
|
/** Implement the Parcelable interface */
|
|
public static final @android.annotation.NonNull Creator<CellIdentity> CREATOR =
|
|
new Creator<CellIdentity>() {
|
|
@Override
|
|
public CellIdentity createFromParcel(Parcel in) {
|
|
int type = in.readInt();
|
|
switch (type) {
|
|
case CellInfo.TYPE_GSM: return CellIdentityGsm.createFromParcelBody(in);
|
|
case CellInfo.TYPE_WCDMA: return CellIdentityWcdma.createFromParcelBody(in);
|
|
case CellInfo.TYPE_CDMA: return CellIdentityCdma.createFromParcelBody(in);
|
|
case CellInfo.TYPE_LTE: return CellIdentityLte.createFromParcelBody(in);
|
|
case CellInfo.TYPE_TDSCDMA:
|
|
return CellIdentityTdscdma.createFromParcelBody(in);
|
|
case CellInfo.TYPE_NR: return CellIdentityNr.createFromParcelBody(in);
|
|
default: throw new IllegalArgumentException("Bad Cell identity Parcel");
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public CellIdentity[] newArray(int size) {
|
|
return new CellIdentity[size];
|
|
}
|
|
};
|
|
|
|
/** @hide */
|
|
protected void log(String s) {
|
|
Rlog.w(mTag, s);
|
|
}
|
|
|
|
/** @hide */
|
|
protected static final int inRangeOrUnavailable(int value, int rangeMin, int rangeMax) {
|
|
if (value < rangeMin || value > rangeMax) return CellInfo.UNAVAILABLE;
|
|
return value;
|
|
}
|
|
|
|
/** @hide */
|
|
protected static final long inRangeOrUnavailable(long value, long rangeMin, long rangeMax) {
|
|
if (value < rangeMin || value > rangeMax) return CellInfo.UNAVAILABLE_LONG;
|
|
return value;
|
|
}
|
|
|
|
/** @hide */
|
|
protected static final int inRangeOrUnavailable(
|
|
int value, int rangeMin, int rangeMax, int special) {
|
|
if ((value < rangeMin || value > rangeMax) && value != special) return CellInfo.UNAVAILABLE;
|
|
return value;
|
|
}
|
|
|
|
/** @hide */
|
|
private static boolean isMcc(@NonNull String mcc) {
|
|
// ensure no out of bounds indexing
|
|
if (mcc.length() != MCC_LENGTH) return false;
|
|
|
|
// Character.isDigit allows all unicode digits, not just [0-9]
|
|
for (int i = 0; i < MCC_LENGTH; i++) {
|
|
if (mcc.charAt(i) < '0' || mcc.charAt(i) > '9') return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/** @hide */
|
|
private static boolean isMnc(@NonNull String mnc) {
|
|
// ensure no out of bounds indexing
|
|
if (mnc.length() < MNC_MIN_LENGTH || mnc.length() > MNC_MAX_LENGTH) return false;
|
|
|
|
// Character.isDigit allows all unicode digits, not just [0-9]
|
|
for (int i = 0; i < mnc.length(); i++) {
|
|
if (mnc.charAt(i) < '0' || mnc.charAt(i) > '9') return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
}
|