1 /* 2 * Copyright (C) 2013 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.compat.annotation.UnsupportedAppUsage; 24 import android.os.Parcel; 25 import android.telephony.gsm.GsmCellLocation; 26 import android.text.TextUtils; 27 import android.util.ArraySet; 28 29 import java.util.Collection; 30 import java.util.Collections; 31 import java.util.Objects; 32 import java.util.Set; 33 34 /** 35 * CellIdentity to represent a unique UMTS cell 36 */ 37 public final class CellIdentityWcdma extends CellIdentity { 38 private static final String TAG = CellIdentityWcdma.class.getSimpleName(); 39 private static final boolean DBG = false; 40 41 private static final int MAX_LAC = 65535; 42 private static final int MAX_CID = 268435455; 43 private static final int MAX_PSC = 511; 44 private static final int MAX_UARFCN = 16383; // a 14 bit number; TS 25.331 ex sec 10.3.8.15 45 46 // 16-bit Location Area Code, 0..65535 47 private final int mLac; 48 // 28-bit UMTS Cell Identity described in TS 25.331, 0..268435455 49 private final int mCid; 50 // 9-bit UMTS Primary Scrambling Code described in TS 25.331, 0..511 51 private final int mPsc; 52 // 16-bit UMTS Absolute RF Channel Number described in TS 25.101 sec. 5.4.4 53 @UnsupportedAppUsage 54 private final int mUarfcn; 55 56 // a list of additional PLMN-IDs reported for this cell 57 private final ArraySet<String> mAdditionalPlmns; 58 59 @Nullable 60 private final ClosedSubscriberGroupInfo mCsgInfo; 61 62 /** 63 * @hide 64 */ CellIdentityWcdma()65 public CellIdentityWcdma() { 66 super(TAG, CellInfo.TYPE_WCDMA, null, null, null, null); 67 mLac = CellInfo.UNAVAILABLE; 68 mCid = CellInfo.UNAVAILABLE; 69 mPsc = CellInfo.UNAVAILABLE; 70 mUarfcn = CellInfo.UNAVAILABLE; 71 mAdditionalPlmns = new ArraySet<>(); 72 mCsgInfo = null; 73 mGlobalCellId = null; 74 } 75 76 /** 77 * public constructor 78 * @param lac 16-bit Location Area Code, 0..65535 79 * @param cid 28-bit UMTS Cell Identity 80 * @param psc 9-bit UMTS Primary Scrambling Code 81 * @param uarfcn 16-bit UMTS Absolute RF Channel Number described in TS 25.101 sec. 5.4.3 82 * @param mccStr 3-digit Mobile Country Code in string format 83 * @param mncStr 2 or 3-digit Mobile Network Code in string format 84 * @param alphal long alpha Operator Name String or Enhanced Operator Name String 85 * @param alphas short alpha Operator Name String or Enhanced Operator Name String 86 * @param additionalPlmns a list of additional PLMN IDs broadcast by the cell 87 * @param csgInfo info about the closed subscriber group broadcast by the cell 88 * 89 * @hide 90 */ CellIdentityWcdma(int lac, int cid, int psc, int uarfcn, @Nullable String mccStr, @Nullable String mncStr, @Nullable String alphal, @Nullable String alphas, @NonNull Collection<String> additionalPlmns, @Nullable ClosedSubscriberGroupInfo csgInfo)91 public CellIdentityWcdma(int lac, int cid, int psc, int uarfcn, @Nullable String mccStr, 92 @Nullable String mncStr, @Nullable String alphal, @Nullable String alphas, 93 @NonNull Collection<String> additionalPlmns, 94 @Nullable ClosedSubscriberGroupInfo csgInfo) { 95 super(TAG, CellInfo.TYPE_WCDMA, mccStr, mncStr, alphal, alphas); 96 mLac = inRangeOrUnavailable(lac, 0, MAX_LAC); 97 mCid = inRangeOrUnavailable(cid, 0, MAX_CID); 98 mPsc = inRangeOrUnavailable(psc, 0, MAX_PSC); 99 mUarfcn = inRangeOrUnavailable(uarfcn, 0, MAX_UARFCN); 100 mAdditionalPlmns = new ArraySet<>(additionalPlmns.size()); 101 for (String plmn : additionalPlmns) { 102 if (isValidPlmn(plmn)) { 103 mAdditionalPlmns.add(plmn); 104 } 105 } 106 mCsgInfo = csgInfo; 107 updateGlobalCellId(); 108 } 109 CellIdentityWcdma(@onNull CellIdentityWcdma cid)110 private CellIdentityWcdma(@NonNull CellIdentityWcdma cid) { 111 this(cid.mLac, cid.mCid, cid.mPsc, cid.mUarfcn, cid.mMccStr, 112 cid.mMncStr, cid.mAlphaLong, cid.mAlphaShort, cid.mAdditionalPlmns, cid.mCsgInfo); 113 } 114 115 /** @hide */ 116 @Override sanitizeLocationInfo()117 public @NonNull CellIdentityWcdma sanitizeLocationInfo() { 118 return new CellIdentityWcdma(CellInfo.UNAVAILABLE, CellInfo.UNAVAILABLE, 119 CellInfo.UNAVAILABLE, CellInfo.UNAVAILABLE, mMccStr, mMncStr, 120 mAlphaLong, mAlphaShort, mAdditionalPlmns, null); 121 } 122 copy()123 @NonNull CellIdentityWcdma copy() { 124 return new CellIdentityWcdma(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 * @return 3-digit Mobile Country Code, 0..999, 141 * {@link android.telephony.CellInfo#UNAVAILABLE UNAVAILABLE} if unavailable. 142 * @deprecated Use {@link #getMccString} instead. 143 */ 144 @Deprecated getMcc()145 public int getMcc() { 146 return (mMccStr != null) ? Integer.valueOf(mMccStr) : CellInfo.UNAVAILABLE; 147 } 148 149 /** 150 * @return 2 or 3-digit Mobile Network Code, 0..999, 151 * {@link android.telephony.CellInfo#UNAVAILABLE UNAVAILABLE} if unavailable. 152 * @deprecated Use {@link #getMncString} instead. 153 */ 154 @Deprecated getMnc()155 public int getMnc() { 156 return (mMncStr != null) ? Integer.valueOf(mMncStr) : CellInfo.UNAVAILABLE; 157 } 158 159 /** 160 * @return 16-bit Location Area Code, 0..65535, 161 * {@link android.telephony.CellInfo#UNAVAILABLE UNAVAILABLE} if unavailable. 162 */ getLac()163 public int getLac() { 164 return mLac; 165 } 166 167 /** 168 * @return CID 169 * 28-bit UMTS Cell Identity described in TS 25.331, 0..268435455, 170 * {@link android.telephony.CellInfo#UNAVAILABLE UNAVAILABLE} if unavailable. 171 */ getCid()172 public int getCid() { 173 return mCid; 174 } 175 176 /** 177 * @return 9-bit UMTS Primary Scrambling Code described in TS 25.331, 0..511, 178 * {@link android.telephony.CellInfo#UNAVAILABLE UNAVAILABLE} if unavailable. 179 */ getPsc()180 public int getPsc() { 181 return mPsc; 182 } 183 184 /** 185 * @return Mobile Country Code in string version, null if unavailable. 186 */ 187 @Nullable getMccString()188 public String getMccString() { 189 return mMccStr; 190 } 191 192 /** 193 * @return Mobile Network Code in string version, null if unavailable. 194 */ 195 @Nullable getMncString()196 public String getMncString() { 197 return mMncStr; 198 } 199 200 /** 201 * @return a 5 or 6 character string (MCC+MNC), null if any field is unknown 202 */ 203 @Nullable getMobileNetworkOperator()204 public String getMobileNetworkOperator() { 205 return (mMccStr == null || mMncStr == null) ? null : mMccStr + mMncStr; 206 } 207 208 @Override hashCode()209 public int hashCode() { 210 return Objects.hash(mLac, mCid, mPsc, mAdditionalPlmns.hashCode(), super.hashCode()); 211 } 212 213 /** 214 * @return 16-bit UMTS Absolute RF Channel Number, 215 * {@link android.telephony.CellInfo#UNAVAILABLE UNAVAILABLE} if unavailable. 216 */ getUarfcn()217 public int getUarfcn() { 218 return mUarfcn; 219 } 220 221 /** @hide */ 222 @Override getChannelNumber()223 public int getChannelNumber() { 224 return mUarfcn; 225 } 226 227 /** 228 * @return a list of additional PLMN IDs supported by this cell. 229 */ 230 @NonNull getAdditionalPlmns()231 public Set<String> getAdditionalPlmns() { 232 return Collections.unmodifiableSet(mAdditionalPlmns); 233 } 234 235 /** 236 * @return closed subscriber group information about the cell if available, otherwise null. 237 */ 238 @Nullable getClosedSubscriberGroupInfo()239 public ClosedSubscriberGroupInfo getClosedSubscriberGroupInfo() { 240 return mCsgInfo; 241 } 242 243 /** @hide */ 244 @NonNull 245 @Override asCellLocation()246 public GsmCellLocation asCellLocation() { 247 GsmCellLocation cl = new GsmCellLocation(); 248 int lac = mLac != CellInfo.UNAVAILABLE ? mLac : -1; 249 int cid = mCid != CellInfo.UNAVAILABLE ? mCid : -1; 250 int psc = mPsc != CellInfo.UNAVAILABLE ? mPsc : -1; 251 cl.setLacAndCid(lac, cid); 252 cl.setPsc(psc); 253 254 return cl; 255 } 256 257 @Override equals(Object other)258 public boolean equals(Object other) { 259 if (this == other) { 260 return true; 261 } 262 263 if (!(other instanceof CellIdentityWcdma)) { 264 return false; 265 } 266 267 CellIdentityWcdma o = (CellIdentityWcdma) other; 268 return mLac == o.mLac 269 && mCid == o.mCid 270 && mPsc == o.mPsc 271 && mUarfcn == o.mUarfcn 272 && TextUtils.equals(mMccStr, o.mMccStr) 273 && TextUtils.equals(mMncStr, o.mMncStr) 274 && mAdditionalPlmns.equals(o.mAdditionalPlmns) 275 && Objects.equals(mCsgInfo, o.mCsgInfo) 276 && super.equals(other); 277 } 278 279 @Override toString()280 public String toString() { 281 return new StringBuilder(TAG) 282 .append(":{ mLac=").append(mLac) 283 .append(" mCid=").append(mCid) 284 .append(" mPsc=").append(mPsc) 285 .append(" mUarfcn=").append(mUarfcn) 286 .append(" mMcc=").append(mMccStr) 287 .append(" mMnc=").append(mMncStr) 288 .append(" mAlphaLong=").append(mAlphaLong) 289 .append(" mAlphaShort=").append(mAlphaShort) 290 .append(" mAdditionalPlmns=").append(mAdditionalPlmns) 291 .append(" mCsgInfo=").append(mCsgInfo) 292 .append("}").toString(); 293 } 294 295 /** Implement the Parcelable interface */ 296 @Override writeToParcel(Parcel dest, int flags)297 public void writeToParcel(Parcel dest, int flags) { 298 if (DBG) log("writeToParcel(Parcel, int): " + toString()); 299 super.writeToParcel(dest, CellInfo.TYPE_WCDMA); 300 dest.writeInt(mLac); 301 dest.writeInt(mCid); 302 dest.writeInt(mPsc); 303 dest.writeInt(mUarfcn); 304 dest.writeArraySet(mAdditionalPlmns); 305 dest.writeParcelable(mCsgInfo, flags); 306 } 307 308 /** Construct from Parcel, type has already been processed */ CellIdentityWcdma(Parcel in)309 private CellIdentityWcdma(Parcel in) { 310 super(TAG, CellInfo.TYPE_WCDMA, in); 311 mLac = in.readInt(); 312 mCid = in.readInt(); 313 mPsc = in.readInt(); 314 mUarfcn = in.readInt(); 315 mAdditionalPlmns = (ArraySet<String>) in.readArraySet(null); 316 mCsgInfo = in.readParcelable(null, android.telephony.ClosedSubscriberGroupInfo.class); 317 318 updateGlobalCellId(); 319 if (DBG) log(toString()); 320 } 321 322 /** Implement the Parcelable interface */ 323 @SuppressWarnings("hiding") 324 public static final @android.annotation.NonNull Creator<CellIdentityWcdma> CREATOR = 325 new Creator<CellIdentityWcdma>() { 326 @Override 327 public CellIdentityWcdma createFromParcel(Parcel in) { 328 in.readInt(); // skip 329 return createFromParcelBody(in); 330 } 331 332 @Override 333 public CellIdentityWcdma[] newArray(int size) { 334 return new CellIdentityWcdma[size]; 335 } 336 }; 337 338 /** @hide */ createFromParcelBody(Parcel in)339 protected static CellIdentityWcdma createFromParcelBody(Parcel in) { 340 return new CellIdentityWcdma(in); 341 } 342 } 343