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