1 /* 2 * Copyright (C) 2018 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.IntRange; 22 import android.annotation.NonNull; 23 import android.annotation.Nullable; 24 import android.os.Parcel; 25 import android.telephony.AccessNetworkConstants.NgranBands.NgranBand; 26 import android.telephony.gsm.GsmCellLocation; 27 import android.util.ArraySet; 28 29 import java.util.Arrays; 30 import java.util.Collection; 31 import java.util.Collections; 32 import java.util.Objects; 33 import java.util.Set; 34 35 /** 36 * Information to represent a unique NR(New Radio 5G) cell. 37 */ 38 public final class CellIdentityNr extends CellIdentity { 39 private static final String TAG = "CellIdentityNr"; 40 41 private static final int MAX_PCI = 1007; 42 private static final int MAX_TAC = 16777215; // 0xffffff 43 private static final int MAX_NRARFCN = 3279165; 44 private static final long MAX_NCI = 68719476735L; 45 46 private final int mNrArfcn; 47 private final int mPci; 48 private final int mTac; 49 private final long mNci; 50 private final int[] mBands; 51 52 // a list of additional PLMN-IDs reported for this cell 53 private final ArraySet<String> mAdditionalPlmns; 54 55 /** @hide */ CellIdentityNr()56 public CellIdentityNr() { 57 super(TAG, CellInfo.TYPE_NR, null, null, null, null); 58 mNrArfcn = CellInfo.UNAVAILABLE; 59 mPci = CellInfo.UNAVAILABLE; 60 mTac = CellInfo.UNAVAILABLE; 61 mNci = CellInfo.UNAVAILABLE; 62 mBands = new int[] {}; 63 mAdditionalPlmns = new ArraySet(); 64 mGlobalCellId = null; 65 } 66 67 /** 68 * 69 * @param pci Physical Cell Id in range [0, 1007]. 70 * @param tac 24-bit Tracking Area Code. 71 * @param nrArfcn NR Absolute Radio Frequency Channel Number, in range [0, 3279165]. 72 * @param bands Bands used by the cell. Band number defined in 3GPP TS 38.101-1 and TS 38.101-2. 73 * @param mccStr 3-digit Mobile Country Code in string format. 74 * @param mncStr 2 or 3-digit Mobile Network Code in string format. 75 * @param nci The 36-bit NR Cell Identity in range [0, 68719476735]. 76 * @param alphal long alpha Operator Name String or Enhanced Operator Name String. 77 * @param alphas short alpha Operator Name String or Enhanced Operator Name String. 78 * @param additionalPlmns a list of additional PLMN IDs broadcast by the cell 79 * 80 * @hide 81 */ CellIdentityNr(int pci, int tac, int nrArfcn, @NonNull @NgranBand int[] bands, @Nullable String mccStr, @Nullable String mncStr, long nci, @Nullable String alphal, @Nullable String alphas, @NonNull Collection<String> additionalPlmns)82 public CellIdentityNr(int pci, int tac, int nrArfcn, @NonNull @NgranBand int[] bands, 83 @Nullable String mccStr, @Nullable String mncStr, long nci, 84 @Nullable String alphal, @Nullable String alphas, 85 @NonNull Collection<String> additionalPlmns) { 86 super(TAG, CellInfo.TYPE_NR, mccStr, mncStr, alphal, alphas); 87 mPci = inRangeOrUnavailable(pci, 0, MAX_PCI); 88 mTac = inRangeOrUnavailable(tac, 0, MAX_TAC); 89 mNrArfcn = inRangeOrUnavailable(nrArfcn, 0, MAX_NRARFCN); 90 // TODO: input validation for bands 91 mBands = bands; 92 mNci = inRangeOrUnavailable(nci, 0, MAX_NCI); 93 mAdditionalPlmns = new ArraySet<>(additionalPlmns.size()); 94 for (String plmn : additionalPlmns) { 95 if (isValidPlmn(plmn)) { 96 mAdditionalPlmns.add(plmn); 97 } 98 } 99 updateGlobalCellId(); 100 } 101 102 /** @hide */ CellIdentityNr(@onNull android.hardware.radio.V1_4.CellIdentityNr cid)103 public CellIdentityNr(@NonNull android.hardware.radio.V1_4.CellIdentityNr cid) { 104 this(cid.pci, cid.tac, cid.nrarfcn, new int[] {}, cid.mcc, cid.mnc, cid.nci, 105 cid.operatorNames.alphaLong, cid.operatorNames.alphaShort, 106 new ArraySet<>()); 107 } 108 109 /** @hide */ CellIdentityNr(@onNull android.hardware.radio.V1_5.CellIdentityNr cid)110 public CellIdentityNr(@NonNull android.hardware.radio.V1_5.CellIdentityNr cid) { 111 this(cid.base.pci, cid.base.tac, cid.base.nrarfcn, 112 cid.bands.stream().mapToInt(Integer::intValue).toArray(), cid.base.mcc, 113 cid.base.mnc, cid.base.nci, cid.base.operatorNames.alphaLong, 114 cid.base.operatorNames.alphaShort, cid.additionalPlmns); 115 } 116 117 /** @hide */ 118 @Override sanitizeLocationInfo()119 public @NonNull CellIdentityNr sanitizeLocationInfo() { 120 return new CellIdentityNr(CellInfo.UNAVAILABLE, CellInfo.UNAVAILABLE, mNrArfcn, 121 mBands, mMccStr, mMncStr, CellInfo.UNAVAILABLE_LONG, mAlphaLong, mAlphaShort, 122 mAdditionalPlmns); 123 } 124 125 /** @hide */ updateGlobalCellId()126 protected void updateGlobalCellId() { 127 mGlobalCellId = null; 128 String plmn = getPlmn(); 129 if (plmn == null) return; 130 131 if (mNci == CellInfo.UNAVAILABLE_LONG) return; 132 133 mGlobalCellId = plmn + formatSimple("%09x", mNci); 134 } 135 136 /** 137 * @return a CellLocation object for this CellIdentity. 138 * @hide 139 */ 140 @NonNull 141 @Override asCellLocation()142 public CellLocation asCellLocation() { 143 GsmCellLocation cl = new GsmCellLocation(); 144 int tac = mTac != CellInfo.UNAVAILABLE ? mTac : -1; 145 cl.setLacAndCid(tac, -1); 146 cl.setPsc(0); 147 return cl; 148 } 149 150 @Override hashCode()151 public int hashCode() { 152 return Objects.hash(super.hashCode(), mPci, mTac, 153 mNrArfcn, Arrays.hashCode(mBands), mNci, mAdditionalPlmns.hashCode()); 154 } 155 156 @Override equals(Object other)157 public boolean equals(Object other) { 158 if (this == other) { 159 return true; 160 } 161 162 if (!(other instanceof CellIdentityNr)) { 163 return false; 164 } 165 166 CellIdentityNr o = (CellIdentityNr) other; 167 return super.equals(o) && mPci == o.mPci && mTac == o.mTac && mNrArfcn == o.mNrArfcn 168 && Arrays.equals(mBands, o.mBands) && mNci == o.mNci 169 && mAdditionalPlmns.equals(o.mAdditionalPlmns); 170 } 171 172 /** 173 * Get the NR(New Radio 5G) Cell Identity. 174 * 175 * @return The 36-bit NR Cell Identity in range [0, 68719476735] or 176 * {@link CellInfo#UNAVAILABLE_LONG} if unknown. 177 */ getNci()178 public long getNci() { 179 return mNci; 180 } 181 182 /** 183 * Get the New Radio Absolute Radio Frequency Channel Number. 184 * 185 * Reference: 3GPP TS 38.101-1 section 5.4.2.1 NR-ARFCN and channel raster. 186 * Reference: 3GPP TS 38.101-2 section 5.4.2.1 NR-ARFCN and channel raster. 187 * 188 * @return Integer value in range [0, 3279165] or {@link CellInfo#UNAVAILABLE} if unknown. 189 */ 190 @IntRange(from = 0, to = 3279165) getNrarfcn()191 public int getNrarfcn() { 192 return mNrArfcn; 193 } 194 195 /** 196 * Get bands of the cell 197 * 198 * Reference: TS 38.101-1 table 5.2-1 199 * Reference: TS 38.101-2 table 5.2-1 200 * 201 * @return Array of band number or empty array if not available. 202 */ 203 @NgranBand 204 @NonNull getBands()205 public int[] getBands() { 206 return Arrays.copyOf(mBands, mBands.length); 207 } 208 209 /** 210 * Get the physical cell id. 211 * @return Integer value in range [0, 1007] or {@link CellInfo#UNAVAILABLE} if unknown. 212 */ 213 @IntRange(from = 0, to = 1007) getPci()214 public int getPci() { 215 return mPci; 216 } 217 218 /** 219 * Get the tracking area code. 220 * @return a 24 bit integer or {@link CellInfo#UNAVAILABLE} if unknown. 221 */ 222 @IntRange(from = 0, to = 16777215) getTac()223 public int getTac() { 224 return mTac; 225 } 226 227 /** 228 * @return Mobile Country Code in string format, or {@code null} if unknown. 229 */ 230 @Nullable getMccString()231 public String getMccString() { 232 return mMccStr; 233 } 234 235 /** 236 * @return Mobile Network Code in string format, or {@code null} if unknown. 237 */ 238 @Nullable getMncString()239 public String getMncString() { 240 return mMncStr; 241 } 242 243 /** @hide */ 244 @Override getChannelNumber()245 public int getChannelNumber() { 246 return mNrArfcn; 247 } 248 249 /** 250 * @return a list of additional PLMN IDs supported by this cell. 251 */ 252 @NonNull getAdditionalPlmns()253 public Set<String> getAdditionalPlmns() { 254 return Collections.unmodifiableSet(mAdditionalPlmns); 255 } 256 257 @Override toString()258 public String toString() { 259 return new StringBuilder(TAG + ":{") 260 .append(" mPci = ").append(mPci) 261 .append(" mTac = ").append(mTac) 262 .append(" mNrArfcn = ").append(mNrArfcn) 263 .append(" mBands = ").append(Arrays.toString(mBands)) 264 .append(" mMcc = ").append(mMccStr) 265 .append(" mMnc = ").append(mMncStr) 266 .append(" mNci = ").append(mNci) 267 .append(" mAlphaLong = ").append(mAlphaLong) 268 .append(" mAlphaShort = ").append(mAlphaShort) 269 .append(" mAdditionalPlmns = ").append(mAdditionalPlmns) 270 .append(" }") 271 .toString(); 272 } 273 274 @Override writeToParcel(Parcel dest, int type)275 public void writeToParcel(Parcel dest, int type) { 276 super.writeToParcel(dest, CellInfo.TYPE_NR); 277 dest.writeInt(mPci); 278 dest.writeInt(mTac); 279 dest.writeInt(mNrArfcn); 280 dest.writeIntArray(mBands); 281 dest.writeLong(mNci); 282 dest.writeArraySet(mAdditionalPlmns); 283 } 284 285 /** Construct from Parcel, type has already been processed */ CellIdentityNr(Parcel in)286 private CellIdentityNr(Parcel in) { 287 super(TAG, CellInfo.TYPE_NR, in); 288 mPci = in.readInt(); 289 mTac = in.readInt(); 290 mNrArfcn = in.readInt(); 291 mBands = in.createIntArray(); 292 mNci = in.readLong(); 293 mAdditionalPlmns = (ArraySet<String>) in.readArraySet(null); 294 295 updateGlobalCellId(); 296 } 297 298 /** Implement the Parcelable interface */ 299 public static final @android.annotation.NonNull Creator<CellIdentityNr> CREATOR = 300 new Creator<CellIdentityNr>() { 301 @Override 302 public CellIdentityNr createFromParcel(Parcel in) { 303 // Skip the type info. 304 in.readInt(); 305 return createFromParcelBody(in); 306 } 307 308 @Override 309 public CellIdentityNr[] newArray(int size) { 310 return new CellIdentityNr[size]; 311 } 312 }; 313 314 /** @hide */ createFromParcelBody(Parcel in)315 protected static CellIdentityNr createFromParcelBody(Parcel in) { 316 return new CellIdentityNr(in); 317 } 318 } 319