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