1 /* 2 * Copyright 2017 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.telephony; 18 19 import static android.text.TextUtils.formatSimple; 20 21 import android.annotation.NonNull; 22 import android.annotation.Nullable; 23 import android.os.Parcel; 24 import android.telephony.gsm.GsmCellLocation; 25 import android.util.ArraySet; 26 27 import java.util.Collection; 28 import java.util.Collections; 29 import java.util.Objects; 30 import java.util.Set; 31 32 /** 33 * CellIdentity is to represent a unique TD-SCDMA cell 34 */ 35 public final class CellIdentityTdscdma extends CellIdentity { 36 private static final String TAG = CellIdentityTdscdma.class.getSimpleName(); 37 private static final boolean DBG = false; 38 39 private static final int MAX_LAC = 65535; 40 private static final int MAX_CID = 268435455; 41 private static final int MAX_CPID = 127; 42 private static final int MAX_UARFCN = 65535; 43 44 // 16-bit Location Area Code, 0..65535, CellInfo.UNAVAILABLE if unknown. 45 private final int mLac; 46 // 28-bit UMTS Cell Identity described in TS 25.331, 0..268435455, CellInfo.UNAVAILABLE 47 // if unknown. 48 private final int mCid; 49 // 8-bit Cell Parameters ID described in TS 25.331 sec 10.3.6.9, 50 // 0..127, CellInfo.UNAVAILABLE if unknown. 51 private final int mCpid; 52 // 16-bit UMTS Absolute RF Channel Number described in TS 25.101 sec. 5.4.3 53 private final int mUarfcn; 54 55 // a list of additional PLMN-IDs reported for this cell 56 private final ArraySet<String> mAdditionalPlmns; 57 58 private ClosedSubscriberGroupInfo mCsgInfo; 59 60 /** 61 * @hide 62 */ CellIdentityTdscdma()63 public CellIdentityTdscdma() { 64 super(TAG, CellInfo.TYPE_TDSCDMA, null, null, null, null); 65 mLac = CellInfo.UNAVAILABLE; 66 mCid = CellInfo.UNAVAILABLE; 67 mCpid = CellInfo.UNAVAILABLE; 68 mUarfcn = CellInfo.UNAVAILABLE; 69 mAdditionalPlmns = new ArraySet<>(); 70 mCsgInfo = null; 71 mGlobalCellId = null; 72 } 73 74 /** 75 * @param mcc 3-digit Mobile Country Code in string format 76 * @param mnc 2 or 3-digit Mobile Network Code in string format 77 * @param lac 16-bit Location Area Code, 0..65535, CellInfo.UNAVAILABLE if unknown 78 * @param cid 28-bit UMTS Cell Identity described in TS 25.331, 0..268435455, 79 * CellInfo.UNAVAILABLE if unknown 80 * @param cpid 8-bit Cell Parameters ID described in TS 25.331, 0..127, 81 * CellInfo.UNAVAILABLE if unknown 82 * @param uarfcn 16-bit UMTS Absolute RF Channel Number described in TS 25.101 sec. 5.4.3 83 * @param alphal long alpha Operator Name String or Enhanced Operator Name String 84 * @param alphas short alpha Operator Name String or Enhanced Operator Name String 85 * @param additionalPlmns a list of additional PLMN IDs broadcast by the cell 86 * @param csgInfo info about the closed subscriber group broadcast by the cell 87 * 88 * @hide 89 */ CellIdentityTdscdma(@ullable String mcc, @Nullable String mnc, int lac, int cid, int cpid, int uarfcn, @Nullable String alphal, @Nullable String alphas, @NonNull Collection<String> additionalPlmns, @Nullable ClosedSubscriberGroupInfo csgInfo)90 public CellIdentityTdscdma(@Nullable String mcc, @Nullable String mnc, int lac, int cid, 91 int cpid, int uarfcn, @Nullable String alphal, @Nullable String alphas, 92 @NonNull Collection<String> additionalPlmns, 93 @Nullable ClosedSubscriberGroupInfo csgInfo) { 94 super(TAG, CellInfo.TYPE_TDSCDMA, mcc, mnc, alphal, alphas); 95 mLac = inRangeOrUnavailable(lac, 0, MAX_LAC); 96 mCid = inRangeOrUnavailable(cid, 0, MAX_CID); 97 mCpid = inRangeOrUnavailable(cpid, 0, MAX_CPID); 98 mUarfcn = inRangeOrUnavailable(uarfcn, 0, MAX_UARFCN); 99 mAdditionalPlmns = new ArraySet<>(additionalPlmns.size()); 100 for (String plmn : additionalPlmns) { 101 if (isValidPlmn(plmn)) { 102 mAdditionalPlmns.add(plmn); 103 } 104 } 105 mCsgInfo = csgInfo; 106 updateGlobalCellId(); 107 } 108 CellIdentityTdscdma(@onNull CellIdentityTdscdma cid)109 private CellIdentityTdscdma(@NonNull CellIdentityTdscdma cid) { 110 this(cid.mMccStr, cid.mMncStr, cid.mLac, cid.mCid, 111 cid.mCpid, cid.mUarfcn, cid.mAlphaLong, 112 cid.mAlphaShort, cid.mAdditionalPlmns, cid.mCsgInfo); 113 } 114 115 /** @hide */ 116 @Override sanitizeLocationInfo()117 public @NonNull CellIdentityTdscdma sanitizeLocationInfo() { 118 return new CellIdentityTdscdma(mMccStr, mMncStr, CellInfo.UNAVAILABLE, CellInfo.UNAVAILABLE, 119 CellInfo.UNAVAILABLE, CellInfo.UNAVAILABLE, mAlphaLong, mAlphaShort, 120 mAdditionalPlmns, null); 121 } 122 copy()123 @NonNull CellIdentityTdscdma copy() { 124 return new CellIdentityTdscdma(this); 125 } 126 127 /** @hide */ 128 @Override updateGlobalCellId()129 protected void updateGlobalCellId() { 130 mGlobalCellId = null; 131 String plmn = getPlmn(); 132 if (plmn == null) return; 133 134 if (mLac == CellInfo.UNAVAILABLE || mCid == CellInfo.UNAVAILABLE) return; 135 136 mGlobalCellId = plmn + formatSimple("%04x%04x", mLac, mCid); 137 } 138 139 /** 140 * Get Mobile Country Code in string format 141 * @return Mobile Country Code in string format, null if unknown 142 */ 143 @Nullable getMccString()144 public String getMccString() { 145 return mMccStr; 146 } 147 148 /** 149 * Get Mobile Network Code in string format 150 * @return Mobile Network Code in string format, null if unknown 151 */ 152 @Nullable getMncString()153 public String getMncString() { 154 return mMncStr; 155 } 156 157 /** 158 * @return a 5 or 6 character string (MCC+MNC), null if any field is unknown 159 */ 160 @Nullable getMobileNetworkOperator()161 public String getMobileNetworkOperator() { 162 return (mMccStr == null || mMncStr == null) ? null : mMccStr + mMncStr; 163 } 164 165 /** 166 * @return 16-bit Location Area Code, 0..65535, 167 * {@link android.telephony.CellInfo#UNAVAILABLE UNAVAILABLE} if unavailable. 168 */ getLac()169 public int getLac() { 170 return mLac; 171 } 172 173 /** 174 * @return 28-bit UMTS Cell Identity described in TS 25.331, 0..268435455, 175 * {@link android.telephony.CellInfo#UNAVAILABLE UNAVAILABLE} if unavailable. 176 */ getCid()177 public int getCid() { 178 return mCid; 179 } 180 181 /** 182 * @return 8-bit Cell Parameters ID described in TS 25.331, 0..127, 183 * {@link android.telephony.CellInfo#UNAVAILABLE UNAVAILABLE} if unavailable. 184 */ getCpid()185 public int getCpid() { 186 return mCpid; 187 } 188 189 /** 190 * @return 16-bit UMTS Absolute RF Channel Number, 191 * {@link android.telephony.CellInfo#UNAVAILABLE UNAVAILABLE} if unavailable. 192 */ getUarfcn()193 public int getUarfcn() { 194 return mUarfcn; 195 } 196 197 /** @hide */ 198 @Override getChannelNumber()199 public int getChannelNumber() { 200 return mUarfcn; 201 } 202 203 /** 204 * @return a list of additional PLMN IDs supported by this cell. 205 */ 206 @NonNull getAdditionalPlmns()207 public Set<String> getAdditionalPlmns() { 208 return Collections.unmodifiableSet(mAdditionalPlmns); 209 } 210 211 /** 212 * @return closed subscriber group information about the cell if available, otherwise null. 213 */ 214 @Nullable getClosedSubscriberGroupInfo()215 public ClosedSubscriberGroupInfo getClosedSubscriberGroupInfo() { 216 return mCsgInfo; 217 } 218 219 /** @hide */ 220 @NonNull 221 @Override asCellLocation()222 public GsmCellLocation asCellLocation() { 223 GsmCellLocation cl = new GsmCellLocation(); 224 int lac = mLac != CellInfo.UNAVAILABLE ? mLac : -1; 225 int cid = mCid != CellInfo.UNAVAILABLE ? mCid : -1; 226 cl.setLacAndCid(lac, cid); 227 cl.setPsc(-1); // There is no PSC for TD-SCDMA; not using this for CPI to stem shenanigans 228 return cl; 229 } 230 231 @Override equals(Object other)232 public boolean equals(Object other) { 233 if (this == other) { 234 return true; 235 } 236 237 if (!(other instanceof CellIdentityTdscdma)) { 238 return false; 239 } 240 241 CellIdentityTdscdma o = (CellIdentityTdscdma) other; 242 return mLac == o.mLac 243 && mCid == o.mCid 244 && mCpid == o.mCpid 245 && mUarfcn == o.mUarfcn 246 && mAdditionalPlmns.equals(o.mAdditionalPlmns) 247 && Objects.equals(mCsgInfo, o.mCsgInfo) 248 && super.equals(other); 249 } 250 251 @Override hashCode()252 public int hashCode() { 253 return Objects.hash(mLac, mCid, mCpid, mUarfcn, 254 mAdditionalPlmns.hashCode(), mCsgInfo, super.hashCode()); 255 } 256 257 @Override toString()258 public String toString() { 259 return new StringBuilder(TAG) 260 .append(":{ mMcc=").append(mMccStr) 261 .append(" mMnc=").append(mMncStr) 262 .append(" mAlphaLong=").append(mAlphaLong) 263 .append(" mAlphaShort=").append(mAlphaShort) 264 .append(" mLac=").append(mLac) 265 .append(" mCid=").append(mCid) 266 .append(" mCpid=").append(mCpid) 267 .append(" mUarfcn=").append(mUarfcn) 268 .append(" mAdditionalPlmns=").append(mAdditionalPlmns) 269 .append(" mCsgInfo=").append(mCsgInfo) 270 .append("}").toString(); 271 } 272 273 /** Implement the Parcelable interface */ 274 @Override describeContents()275 public int describeContents() { 276 return 0; 277 } 278 279 /** Implement the Parcelable interface */ 280 @Override writeToParcel(Parcel dest, int flags)281 public void writeToParcel(Parcel dest, int flags) { 282 if (DBG) log("writeToParcel(Parcel, int): " + toString()); 283 super.writeToParcel(dest, CellInfo.TYPE_TDSCDMA); 284 dest.writeInt(mLac); 285 dest.writeInt(mCid); 286 dest.writeInt(mCpid); 287 dest.writeInt(mUarfcn); 288 dest.writeArraySet(mAdditionalPlmns); 289 dest.writeParcelable(mCsgInfo, flags); 290 } 291 292 /** Construct from Parcel, type has already been processed */ CellIdentityTdscdma(Parcel in)293 private CellIdentityTdscdma(Parcel in) { 294 super(TAG, CellInfo.TYPE_TDSCDMA, in); 295 mLac = in.readInt(); 296 mCid = in.readInt(); 297 mCpid = in.readInt(); 298 mUarfcn = in.readInt(); 299 mAdditionalPlmns = (ArraySet<String>) in.readArraySet(null); 300 mCsgInfo = in.readParcelable(null, android.telephony.ClosedSubscriberGroupInfo.class); 301 302 updateGlobalCellId(); 303 if (DBG) log(toString()); 304 } 305 306 /** Implement the Parcelable interface */ 307 @SuppressWarnings("hiding") 308 @NonNull 309 public static final Creator<CellIdentityTdscdma> CREATOR = 310 new Creator<CellIdentityTdscdma>() { 311 @Override 312 public @NonNull CellIdentityTdscdma createFromParcel(Parcel in) { 313 in.readInt(); // skip 314 return createFromParcelBody(in); 315 } 316 317 @Override 318 public @NonNull CellIdentityTdscdma[] newArray(int size) { 319 return new CellIdentityTdscdma[size]; 320 } 321 }; 322 323 /** @hide */ createFromParcelBody(Parcel in)324 protected static CellIdentityTdscdma createFromParcelBody(Parcel in) { 325 return new CellIdentityTdscdma(in); 326 } 327 } 328