1 /* 2 * Copyright (C) 2012 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 android.annotation.NonNull; 20 import android.annotation.Nullable; 21 import android.compat.annotation.UnsupportedAppUsage; 22 import android.os.Build; 23 import android.os.Parcel; 24 import android.telephony.gsm.GsmCellLocation; 25 import android.text.TextUtils; 26 import android.util.ArraySet; 27 28 import java.util.Arrays; 29 import java.util.Collection; 30 import java.util.Collections; 31 import java.util.Objects; 32 import java.util.Set; 33 34 /** 35 * CellIdentity is to represent a unique LTE cell 36 */ 37 public final class CellIdentityLte extends CellIdentity { 38 private static final String TAG = CellIdentityLte.class.getSimpleName(); 39 private static final boolean DBG = false; 40 41 private static final int MAX_CI = 268435455; 42 private static final int MAX_PCI = 503; 43 private static final int MAX_TAC = 65535; 44 private static final int MAX_EARFCN = 262143; 45 private static final int MAX_BANDWIDTH = 20000; 46 47 // 28-bit cell identity 48 private final int mCi; 49 // physical cell id 0..503 50 private final int mPci; 51 // 16-bit tracking area code 52 private final int mTac; 53 // 18-bit Absolute RF Channel Number 54 private final int mEarfcn; 55 // cell bandwidth, in kHz 56 private final int mBandwidth; 57 // cell bands 58 private final int[] mBands; 59 60 // a list of additional PLMN-IDs reported for this cell 61 private final ArraySet<String> mAdditionalPlmns; 62 63 private ClosedSubscriberGroupInfo mCsgInfo; 64 65 /** 66 * @hide 67 */ 68 @UnsupportedAppUsage CellIdentityLte()69 public CellIdentityLte() { 70 super(TAG, CellInfo.TYPE_LTE, null, null, null, null); 71 mCi = CellInfo.UNAVAILABLE; 72 mPci = CellInfo.UNAVAILABLE; 73 mTac = CellInfo.UNAVAILABLE; 74 mEarfcn = CellInfo.UNAVAILABLE; 75 mBands = new int[] {}; 76 mBandwidth = CellInfo.UNAVAILABLE; 77 mAdditionalPlmns = new ArraySet<>(); 78 mCsgInfo = null; 79 mGlobalCellId = null; 80 } 81 82 /** 83 * 84 * @param mcc 3-digit Mobile Country Code, 0..999 85 * @param mnc 2 or 3-digit Mobile Network Code, 0..999 86 * @param ci 28-bit Cell Identity 87 * @param pci Physical Cell Id 0..503 88 * @param tac 16-bit Tracking Area Code 89 * 90 * @hide 91 */ 92 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) CellIdentityLte(int mcc, int mnc, int ci, int pci, int tac)93 public CellIdentityLte(int mcc, int mnc, int ci, int pci, int tac) { 94 this(ci, pci, tac, CellInfo.UNAVAILABLE, new int[] {}, CellInfo.UNAVAILABLE, 95 String.valueOf(mcc), String.valueOf(mnc), null, null, new ArraySet<>(), 96 null); 97 } 98 99 /** 100 * 101 * @param ci 28-bit Cell Identity 102 * @param pci Physical Cell Id 0..503 103 * @param tac 16-bit Tracking Area Code 104 * @param earfcn 18-bit LTE Absolute RF Channel Number 105 * @param bandwidth cell bandwidth in kHz 106 * @param mccStr 3-digit Mobile Country Code in string format 107 * @param mncStr 2 or 3-digit Mobile Network Code in string format 108 * @param alphal long alpha Operator Name String or Enhanced Operator Name String 109 * @param alphas short alpha Operator Name String or Enhanced Operator Name String 110 * @param additionalPlmns a list of additional PLMN IDs broadcast by the cell 111 * @param csgInfo info about the closed subscriber group broadcast by the cell 112 * 113 * @hide 114 */ CellIdentityLte(int ci, int pci, int tac, int earfcn, @NonNull int[] bands, int bandwidth, @Nullable String mccStr, @Nullable String mncStr, @Nullable String alphal, @Nullable String alphas, @NonNull Collection<String> additionalPlmns, @Nullable ClosedSubscriberGroupInfo csgInfo)115 public CellIdentityLte(int ci, int pci, int tac, int earfcn, @NonNull int[] bands, 116 int bandwidth, @Nullable String mccStr, @Nullable String mncStr, 117 @Nullable String alphal, @Nullable String alphas, 118 @NonNull Collection<String> additionalPlmns, 119 @Nullable ClosedSubscriberGroupInfo csgInfo) { 120 super(TAG, CellInfo.TYPE_LTE, mccStr, mncStr, alphal, alphas); 121 mCi = inRangeOrUnavailable(ci, 0, MAX_CI); 122 mPci = inRangeOrUnavailable(pci, 0, MAX_PCI); 123 mTac = inRangeOrUnavailable(tac, 0, MAX_TAC); 124 mEarfcn = inRangeOrUnavailable(earfcn, 0, MAX_EARFCN); 125 mBands = bands; 126 mBandwidth = inRangeOrUnavailable(bandwidth, 0, MAX_BANDWIDTH); 127 mAdditionalPlmns = new ArraySet<>(additionalPlmns.size()); 128 for (String plmn : additionalPlmns) { 129 if (isValidPlmn(plmn)) { 130 mAdditionalPlmns.add(plmn); 131 } 132 } 133 mCsgInfo = csgInfo; 134 updateGlobalCellId(); 135 } 136 137 /** @hide */ CellIdentityLte(@onNull android.hardware.radio.V1_0.CellIdentityLte cid)138 public CellIdentityLte(@NonNull android.hardware.radio.V1_0.CellIdentityLte cid) { 139 this(cid.ci, cid.pci, cid.tac, cid.earfcn, new int[] {}, 140 CellInfo.UNAVAILABLE, cid.mcc, cid.mnc, "", "", new ArraySet<>(), null); 141 } 142 143 /** @hide */ CellIdentityLte(@onNull android.hardware.radio.V1_2.CellIdentityLte cid)144 public CellIdentityLte(@NonNull android.hardware.radio.V1_2.CellIdentityLte cid) { 145 this(cid.base.ci, cid.base.pci, cid.base.tac, cid.base.earfcn, new int[] {}, 146 cid.bandwidth, cid.base.mcc, cid.base.mnc, cid.operatorNames.alphaLong, 147 cid.operatorNames.alphaShort, new ArraySet<>(), null); 148 } 149 150 /** @hide */ CellIdentityLte(@onNull android.hardware.radio.V1_5.CellIdentityLte cid)151 public CellIdentityLte(@NonNull android.hardware.radio.V1_5.CellIdentityLte cid) { 152 this(cid.base.base.ci, cid.base.base.pci, cid.base.base.tac, cid.base.base.earfcn, 153 cid.bands.stream().mapToInt(Integer::intValue).toArray(), cid.base.bandwidth, 154 cid.base.base.mcc, cid.base.base.mnc, cid.base.operatorNames.alphaLong, 155 cid.base.operatorNames.alphaShort, cid.additionalPlmns, 156 cid.optionalCsgInfo.getDiscriminator() 157 == android.hardware.radio.V1_5.OptionalCsgInfo.hidl_discriminator.csgInfo 158 ? new ClosedSubscriberGroupInfo(cid.optionalCsgInfo.csgInfo()) 159 : null); 160 } 161 CellIdentityLte(@onNull CellIdentityLte cid)162 private CellIdentityLte(@NonNull CellIdentityLte cid) { 163 this(cid.mCi, cid.mPci, cid.mTac, cid.mEarfcn, cid.mBands, cid.mBandwidth, cid.mMccStr, 164 cid.mMncStr, cid.mAlphaLong, cid.mAlphaShort, cid.mAdditionalPlmns, cid.mCsgInfo); 165 } 166 167 /** @hide */ 168 @Override sanitizeLocationInfo()169 public @NonNull CellIdentityLte sanitizeLocationInfo() { 170 return new CellIdentityLte(CellInfo.UNAVAILABLE, CellInfo.UNAVAILABLE, CellInfo.UNAVAILABLE, 171 CellInfo.UNAVAILABLE, mBands, CellInfo.UNAVAILABLE, 172 mMccStr, mMncStr, mAlphaLong, mAlphaShort, mAdditionalPlmns, null); 173 } 174 copy()175 @NonNull CellIdentityLte copy() { 176 return new CellIdentityLte(this); 177 } 178 179 /** @hide */ 180 @Override updateGlobalCellId()181 protected void updateGlobalCellId() { 182 mGlobalCellId = null; 183 String plmn = getPlmn(); 184 if (plmn == null) return; 185 186 if (mCi == CellInfo.UNAVAILABLE) return; 187 188 mGlobalCellId = plmn + String.format("%07x", mCi); 189 } 190 191 /** 192 * @return 3-digit Mobile Country Code, 0..999, 193 * {@link android.telephony.CellInfo#UNAVAILABLE UNAVAILABLE} if unavailable. 194 * @deprecated Use {@link #getMccString} instead. 195 */ 196 @Deprecated getMcc()197 public int getMcc() { 198 return (mMccStr != null) ? Integer.valueOf(mMccStr) : CellInfo.UNAVAILABLE; 199 } 200 201 /** 202 * @return 2 or 3-digit Mobile Network Code, 0..999, 203 * {@link android.telephony.CellInfo#UNAVAILABLE UNAVAILABLE} if unavailable. 204 * @deprecated Use {@link #getMncString} instead. 205 */ 206 @Deprecated getMnc()207 public int getMnc() { 208 return (mMncStr != null) ? Integer.valueOf(mMncStr) : CellInfo.UNAVAILABLE; 209 } 210 211 /** 212 * @return 28-bit Cell Identity, 213 * {@link android.telephony.CellInfo#UNAVAILABLE UNAVAILABLE} if unavailable. 214 */ getCi()215 public int getCi() { 216 return mCi; 217 } 218 219 /** 220 * @return Physical Cell Id 0..503, 221 * {@link android.telephony.CellInfo#UNAVAILABLE UNAVAILABLE} if unavailable. 222 */ getPci()223 public int getPci() { 224 return mPci; 225 } 226 227 /** 228 * @return 16-bit Tracking Area Code, 229 * {@link android.telephony.CellInfo#UNAVAILABLE UNAVAILABLE} if unavailable. 230 */ getTac()231 public int getTac() { 232 return mTac; 233 } 234 235 /** 236 * @return 18-bit Absolute RF Channel Number, 237 * {@link android.telephony.CellInfo#UNAVAILABLE UNAVAILABLE} if unavailable. 238 */ getEarfcn()239 public int getEarfcn() { 240 return mEarfcn; 241 } 242 243 /** 244 * Get bands of the cell 245 * 246 * Reference: 3GPP TS 36.101 section 5.5 247 * 248 * @return Array of band number or empty array if not available. 249 */ 250 @NonNull getBands()251 public int[] getBands() { 252 return Arrays.copyOf(mBands, mBands.length); 253 } 254 255 /** 256 * @return Cell bandwidth in kHz, 257 * {@link android.telephony.CellInfo#UNAVAILABLE UNAVAILABLE} if unavailable. 258 */ getBandwidth()259 public int getBandwidth() { 260 return mBandwidth; 261 } 262 263 /** 264 * @return Mobile Country Code in string format, null if unavailable. 265 */ 266 @Nullable getMccString()267 public String getMccString() { 268 return mMccStr; 269 } 270 271 /** 272 * @return Mobile Network Code in string format, null if unavailable. 273 */ 274 @Nullable getMncString()275 public String getMncString() { 276 return mMncStr; 277 } 278 279 /** 280 * @return a 5 or 6 character string (MCC+MNC), null if any field is unknown. 281 */ 282 @Nullable getMobileNetworkOperator()283 public String getMobileNetworkOperator() { 284 return (mMccStr == null || mMncStr == null) ? null : mMccStr + mMncStr; 285 } 286 287 /** @hide */ 288 @Override getChannelNumber()289 public int getChannelNumber() { 290 return mEarfcn; 291 } 292 293 /** 294 * @return a list of additional PLMN IDs supported by this cell. 295 */ 296 @NonNull getAdditionalPlmns()297 public Set<String> getAdditionalPlmns() { 298 return Collections.unmodifiableSet(mAdditionalPlmns); 299 } 300 301 /** 302 * @return closed subscriber group information about the cell if available, otherwise null. 303 */ 304 @Nullable getClosedSubscriberGroupInfo()305 public ClosedSubscriberGroupInfo getClosedSubscriberGroupInfo() { 306 return mCsgInfo; 307 } 308 309 /** 310 * A hack to allow tunneling of LTE information via GsmCellLocation 311 * so that older Network Location Providers can return some information 312 * on LTE only networks, see bug 9228974. 313 * 314 * The tunnel'd LTE information is returned as follows: 315 * LAC = TAC field 316 * CID = CI field 317 * PSC = 0. 318 * 319 * @hide 320 */ 321 @NonNull 322 @Override asCellLocation()323 public GsmCellLocation asCellLocation() { 324 GsmCellLocation cl = new GsmCellLocation(); 325 int tac = mTac != CellInfo.UNAVAILABLE ? mTac : -1; 326 int cid = mCi != CellInfo.UNAVAILABLE ? mCi : -1; 327 cl.setLacAndCid(tac, cid); 328 cl.setPsc(0); 329 return cl; 330 } 331 332 @Override hashCode()333 public int hashCode() { 334 return Objects.hash(mCi, mPci, mTac, mEarfcn, Arrays.hashCode(mBands), 335 mBandwidth, mAdditionalPlmns.hashCode(), mCsgInfo, super.hashCode()); 336 } 337 338 @Override equals(Object other)339 public boolean equals(Object other) { 340 if (this == other) { 341 return true; 342 } 343 344 if (!(other instanceof CellIdentityLte)) { 345 return false; 346 } 347 348 CellIdentityLte o = (CellIdentityLte) other; 349 return mCi == o.mCi 350 && mPci == o.mPci 351 && mTac == o.mTac 352 && mEarfcn == o.mEarfcn 353 && Arrays.equals(mBands, o.mBands) 354 && mBandwidth == o.mBandwidth 355 && TextUtils.equals(mMccStr, o.mMccStr) 356 && TextUtils.equals(mMncStr, o.mMncStr) 357 && mAdditionalPlmns.equals(o.mAdditionalPlmns) 358 && Objects.equals(mCsgInfo, o.mCsgInfo) 359 && super.equals(other); 360 } 361 362 @Override toString()363 public String toString() { 364 return new StringBuilder(TAG) 365 .append(":{ mCi=").append(mCi) 366 .append(" mPci=").append(mPci) 367 .append(" mTac=").append(mTac) 368 .append(" mEarfcn=").append(mEarfcn) 369 .append(" mBands=").append(mBands) 370 .append(" mBandwidth=").append(mBandwidth) 371 .append(" mMcc=").append(mMccStr) 372 .append(" mMnc=").append(mMncStr) 373 .append(" mAlphaLong=").append(mAlphaLong) 374 .append(" mAlphaShort=").append(mAlphaShort) 375 .append(" mAdditionalPlmns=").append(mAdditionalPlmns) 376 .append(" mCsgInfo=").append(mCsgInfo) 377 .append("}").toString(); 378 } 379 380 /** Implement the Parcelable interface */ 381 @Override writeToParcel(Parcel dest, int flags)382 public void writeToParcel(Parcel dest, int flags) { 383 if (DBG) log("writeToParcel(Parcel, int): " + toString()); 384 super.writeToParcel(dest, CellInfo.TYPE_LTE); 385 dest.writeInt(mCi); 386 dest.writeInt(mPci); 387 dest.writeInt(mTac); 388 dest.writeInt(mEarfcn); 389 dest.writeIntArray(mBands); 390 dest.writeInt(mBandwidth); 391 dest.writeArraySet(mAdditionalPlmns); 392 dest.writeParcelable(mCsgInfo, flags); 393 } 394 395 /** Construct from Parcel, type has already been processed */ CellIdentityLte(Parcel in)396 private CellIdentityLte(Parcel in) { 397 super(TAG, CellInfo.TYPE_LTE, in); 398 mCi = in.readInt(); 399 mPci = in.readInt(); 400 mTac = in.readInt(); 401 mEarfcn = in.readInt(); 402 mBands = in.createIntArray(); 403 mBandwidth = in.readInt(); 404 mAdditionalPlmns = (ArraySet<String>) in.readArraySet(null); 405 mCsgInfo = in.readParcelable(null); 406 407 updateGlobalCellId(); 408 if (DBG) log(toString()); 409 } 410 411 /** Implement the Parcelable interface */ 412 @SuppressWarnings("hiding") 413 public static final @android.annotation.NonNull Creator<CellIdentityLte> CREATOR = 414 new Creator<CellIdentityLte>() { 415 @Override 416 public CellIdentityLte createFromParcel(Parcel in) { 417 in.readInt(); // skip; 418 return createFromParcelBody(in); 419 } 420 421 @Override 422 public CellIdentityLte[] newArray(int size) { 423 return new CellIdentityLte[size]; 424 } 425 }; 426 427 /** @hide */ createFromParcelBody(Parcel in)428 protected static CellIdentityLte createFromParcelBody(Parcel in) { 429 return new CellIdentityLte(in); 430 } 431 } 432