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.ElapsedRealtimeLong; 20 import android.annotation.IntDef; 21 import android.annotation.NonNull; 22 import android.compat.annotation.UnsupportedAppUsage; 23 import android.hardware.radio.V1_4.CellInfo.Info; 24 import android.hardware.radio.V1_5.CellInfo.CellInfoRatSpecificInfo; 25 import android.os.Parcel; 26 import android.os.Parcelable; 27 28 import com.android.internal.annotations.VisibleForTesting; 29 30 import java.lang.annotation.Retention; 31 import java.lang.annotation.RetentionPolicy; 32 import java.util.Objects; 33 34 /** 35 * Immutable cell information from a point in time. 36 */ 37 public abstract class CellInfo implements Parcelable { 38 39 /** 40 * This value indicates that the integer field is unreported. 41 */ 42 public static final int UNAVAILABLE = Integer.MAX_VALUE; 43 44 /** 45 * This value indicates that the long field is unreported. 46 */ 47 public static final long UNAVAILABLE_LONG = Long.MAX_VALUE; 48 49 /** 50 * Cell identity type 51 * @hide 52 */ 53 @Retention(RetentionPolicy.SOURCE) 54 @IntDef(prefix = "TYPE_", 55 value = {TYPE_GSM, TYPE_CDMA, TYPE_LTE, TYPE_WCDMA, TYPE_TDSCDMA, TYPE_NR}) 56 public @interface Type {} 57 58 /** 59 * Unknown cell identity type 60 * @hide 61 */ 62 public static final int TYPE_UNKNOWN = 0; 63 64 /** 65 * GSM cell identity type 66 * @hide 67 */ 68 public static final int TYPE_GSM = 1; 69 70 /** 71 * CDMA cell identity type 72 * @hide 73 */ 74 public static final int TYPE_CDMA = 2; 75 76 /** 77 * LTE cell identity type 78 * @hide 79 */ 80 public static final int TYPE_LTE = 3; 81 82 /** 83 * WCDMA cell identity type 84 * @hide 85 */ 86 public static final int TYPE_WCDMA = 4; 87 88 /** 89 * TD-SCDMA cell identity type 90 * @hide 91 */ 92 public static final int TYPE_TDSCDMA = 5; 93 94 /** 95 * 5G cell identity type 96 * @hide 97 */ 98 public static final int TYPE_NR = 6; 99 100 // Type to distinguish where time stamp gets recorded. 101 102 /** @hide */ 103 @UnsupportedAppUsage 104 public static final int TIMESTAMP_TYPE_UNKNOWN = 0; 105 /** @hide */ 106 @UnsupportedAppUsage 107 public static final int TIMESTAMP_TYPE_ANTENNA = 1; 108 /** @hide */ 109 @UnsupportedAppUsage 110 public static final int TIMESTAMP_TYPE_MODEM = 2; 111 /** @hide */ 112 @UnsupportedAppUsage 113 public static final int TIMESTAMP_TYPE_OEM_RIL = 3; 114 /** @hide */ 115 @UnsupportedAppUsage 116 public static final int TIMESTAMP_TYPE_JAVA_RIL = 4; 117 118 /** @hide */ 119 @Retention(RetentionPolicy.SOURCE) 120 @IntDef({ 121 CONNECTION_NONE, 122 CONNECTION_PRIMARY_SERVING, 123 CONNECTION_SECONDARY_SERVING, 124 CONNECTION_UNKNOWN 125 }) 126 public @interface CellConnectionStatus {} 127 128 /** 129 * Cell is not a serving cell. 130 * 131 * <p>The cell has been measured but is neither a camped nor serving cell (3GPP 36.304). 132 */ 133 public static final int CONNECTION_NONE = 0; 134 135 /** UE is connected to cell for signalling and possibly data (3GPP 36.331, 25.331). */ 136 public static final int CONNECTION_PRIMARY_SERVING = 1; 137 138 /** UE is connected to cell for data (3GPP 36.331, 25.331). */ 139 public static final int CONNECTION_SECONDARY_SERVING = 2; 140 141 /** Connection status is unknown. */ 142 public static final int CONNECTION_UNKNOWN = Integer.MAX_VALUE; 143 144 /** A cell connection status */ 145 private int mCellConnectionStatus; 146 147 // True if device is mRegistered to the mobile network 148 private boolean mRegistered; 149 150 // Observation time stamped as type in nanoseconds since boot 151 private long mTimeStamp; 152 153 /** @hide */ CellInfo()154 protected CellInfo() { 155 this.mRegistered = false; 156 this.mTimeStamp = Long.MAX_VALUE; 157 this.mCellConnectionStatus = CONNECTION_NONE; 158 } 159 160 /** @hide */ CellInfo(CellInfo ci)161 protected CellInfo(CellInfo ci) { 162 this.mRegistered = ci.mRegistered; 163 this.mTimeStamp = ci.mTimeStamp; 164 this.mCellConnectionStatus = ci.mCellConnectionStatus; 165 } 166 167 /** 168 * True if the phone is registered to a mobile network that provides service on this cell 169 * and this cell is being used or would be used for network signaling. 170 */ isRegistered()171 public boolean isRegistered() { 172 return mRegistered; 173 } 174 175 /** @hide */ setRegistered(boolean registered)176 public void setRegistered(boolean registered) { 177 mRegistered = registered; 178 } 179 180 /** 181 * Approximate time this cell information was received from the modem. 182 * 183 * @return a time stamp in millis since boot. 184 */ 185 @ElapsedRealtimeLong getTimestampMillis()186 public long getTimestampMillis() { 187 return mTimeStamp / 1000000; 188 } 189 190 /** 191 * Approximate time this cell information was received from the modem. 192 * 193 * @return a time stamp in nanos since boot. 194 * @deprecated Use {@link #getTimestampMillis} instead. 195 */ 196 @Deprecated getTimeStamp()197 public long getTimeStamp() { 198 return mTimeStamp; 199 } 200 201 /** @hide */ 202 @VisibleForTesting setTimeStamp(long ts)203 public void setTimeStamp(long ts) { 204 mTimeStamp = ts; 205 } 206 207 /** 208 * @return a {@link CellIdentity} instance. 209 */ 210 @NonNull getCellIdentity()211 public abstract CellIdentity getCellIdentity(); 212 213 /** 214 * @return a {@link CellSignalStrength} instance. 215 */ 216 @NonNull getCellSignalStrength()217 public abstract CellSignalStrength getCellSignalStrength(); 218 219 /** @hide */ sanitizeLocationInfo()220 public CellInfo sanitizeLocationInfo() { 221 return null; 222 } 223 224 /** 225 * Gets the connection status of this cell. 226 * 227 * @see #CONNECTION_NONE 228 * @see #CONNECTION_PRIMARY_SERVING 229 * @see #CONNECTION_SECONDARY_SERVING 230 * @see #CONNECTION_UNKNOWN 231 * 232 * @return The connection status of the cell. 233 */ 234 @CellConnectionStatus getCellConnectionStatus()235 public int getCellConnectionStatus() { 236 return mCellConnectionStatus; 237 } 238 /** @hide */ setCellConnectionStatus(@ellConnectionStatus int cellConnectionStatus)239 public void setCellConnectionStatus(@CellConnectionStatus int cellConnectionStatus) { 240 mCellConnectionStatus = cellConnectionStatus; 241 } 242 243 @Override hashCode()244 public int hashCode() { 245 return Objects.hash(mCellConnectionStatus, mRegistered, mTimeStamp); 246 } 247 248 @Override equals(Object o)249 public boolean equals(Object o) { 250 if (this == o) return true; 251 if (!(o instanceof CellInfo)) return false; 252 CellInfo cellInfo = (CellInfo) o; 253 return mCellConnectionStatus == cellInfo.mCellConnectionStatus 254 && mRegistered == cellInfo.mRegistered 255 && mTimeStamp == cellInfo.mTimeStamp; 256 } 257 258 @Override toString()259 public String toString() { 260 StringBuffer sb = new StringBuffer(); 261 262 sb.append("mRegistered=").append(mRegistered ? "YES" : "NO"); 263 sb.append(" mTimeStamp=").append(mTimeStamp).append("ns"); 264 sb.append(" mCellConnectionStatus=").append(mCellConnectionStatus); 265 266 return sb.toString(); 267 } 268 269 /** 270 * Implement the Parcelable interface 271 */ 272 @Override describeContents()273 public int describeContents() { 274 return 0; 275 } 276 277 /** Implement the Parcelable interface */ 278 @Override writeToParcel(Parcel dest, int flags)279 public abstract void writeToParcel(Parcel dest, int flags); 280 281 /** 282 * Used by child classes for parceling. 283 * 284 * @hide 285 */ writeToParcel(Parcel dest, int flags, int type)286 protected void writeToParcel(Parcel dest, int flags, int type) { 287 dest.writeInt(type); 288 dest.writeInt(mRegistered ? 1 : 0); 289 dest.writeLong(mTimeStamp); 290 dest.writeInt(mCellConnectionStatus); 291 } 292 293 /** 294 * Used by child classes for parceling 295 * 296 * @hide 297 */ CellInfo(Parcel in)298 protected CellInfo(Parcel in) { 299 mRegistered = (in.readInt() == 1) ? true : false; 300 mTimeStamp = in.readLong(); 301 mCellConnectionStatus = in.readInt(); 302 } 303 304 /** Implement the Parcelable interface */ 305 public static final @android.annotation.NonNull Creator<CellInfo> CREATOR = new Creator<CellInfo>() { 306 @Override 307 public CellInfo createFromParcel(Parcel in) { 308 int type = in.readInt(); 309 switch (type) { 310 case TYPE_GSM: return CellInfoGsm.createFromParcelBody(in); 311 case TYPE_CDMA: return CellInfoCdma.createFromParcelBody(in); 312 case TYPE_LTE: return CellInfoLte.createFromParcelBody(in); 313 case TYPE_WCDMA: return CellInfoWcdma.createFromParcelBody(in); 314 case TYPE_TDSCDMA: return CellInfoTdscdma.createFromParcelBody(in); 315 case TYPE_NR: return CellInfoNr.createFromParcelBody(in); 316 default: throw new RuntimeException("Bad CellInfo Parcel"); 317 } 318 } 319 320 @Override 321 public CellInfo[] newArray(int size) { 322 return new CellInfo[size]; 323 } 324 }; 325 326 /** @hide */ CellInfo(android.hardware.radio.V1_0.CellInfo ci)327 protected CellInfo(android.hardware.radio.V1_0.CellInfo ci) { 328 this.mRegistered = ci.registered; 329 this.mTimeStamp = ci.timeStamp; 330 this.mCellConnectionStatus = CONNECTION_UNKNOWN; 331 } 332 333 /** @hide */ CellInfo(android.hardware.radio.V1_2.CellInfo ci)334 protected CellInfo(android.hardware.radio.V1_2.CellInfo ci) { 335 this.mRegistered = ci.registered; 336 this.mTimeStamp = ci.timeStamp; 337 this.mCellConnectionStatus = ci.connectionStatus; 338 } 339 340 /** @hide */ CellInfo(android.hardware.radio.V1_4.CellInfo ci, long timeStamp)341 protected CellInfo(android.hardware.radio.V1_4.CellInfo ci, long timeStamp) { 342 this.mRegistered = ci.isRegistered; 343 this.mTimeStamp = timeStamp; 344 this.mCellConnectionStatus = ci.connectionStatus; 345 } 346 347 /** @hide */ CellInfo(android.hardware.radio.V1_5.CellInfo ci, long timeStamp)348 protected CellInfo(android.hardware.radio.V1_5.CellInfo ci, long timeStamp) { 349 this.mRegistered = ci.registered; 350 this.mTimeStamp = timeStamp; 351 this.mCellConnectionStatus = ci.connectionStatus; 352 } 353 354 /** @hide */ create(android.hardware.radio.V1_0.CellInfo ci)355 public static CellInfo create(android.hardware.radio.V1_0.CellInfo ci) { 356 if (ci == null) return null; 357 switch(ci.cellInfoType) { 358 case android.hardware.radio.V1_0.CellInfoType.GSM: return new CellInfoGsm(ci); 359 case android.hardware.radio.V1_0.CellInfoType.CDMA: return new CellInfoCdma(ci); 360 case android.hardware.radio.V1_0.CellInfoType.LTE: return new CellInfoLte(ci); 361 case android.hardware.radio.V1_0.CellInfoType.WCDMA: return new CellInfoWcdma(ci); 362 case android.hardware.radio.V1_0.CellInfoType.TD_SCDMA: return new CellInfoTdscdma(ci); 363 default: return null; 364 } 365 } 366 367 /** @hide */ create(android.hardware.radio.V1_2.CellInfo ci)368 public static CellInfo create(android.hardware.radio.V1_2.CellInfo ci) { 369 if (ci == null) return null; 370 switch(ci.cellInfoType) { 371 case android.hardware.radio.V1_0.CellInfoType.GSM: return new CellInfoGsm(ci); 372 case android.hardware.radio.V1_0.CellInfoType.CDMA: return new CellInfoCdma(ci); 373 case android.hardware.radio.V1_0.CellInfoType.LTE: return new CellInfoLte(ci); 374 case android.hardware.radio.V1_0.CellInfoType.WCDMA: return new CellInfoWcdma(ci); 375 case android.hardware.radio.V1_0.CellInfoType.TD_SCDMA: return new CellInfoTdscdma(ci); 376 default: return null; 377 } 378 } 379 380 /** @hide */ create(android.hardware.radio.V1_4.CellInfo ci, long timeStamp)381 public static CellInfo create(android.hardware.radio.V1_4.CellInfo ci, long timeStamp) { 382 if (ci == null) return null; 383 switch (ci.info.getDiscriminator()) { 384 case Info.hidl_discriminator.gsm: return new CellInfoGsm(ci, timeStamp); 385 case Info.hidl_discriminator.cdma: return new CellInfoCdma(ci, timeStamp); 386 case Info.hidl_discriminator.lte: return new CellInfoLte(ci, timeStamp); 387 case Info.hidl_discriminator.wcdma: return new CellInfoWcdma(ci, timeStamp); 388 case Info.hidl_discriminator.tdscdma: return new CellInfoTdscdma(ci, timeStamp); 389 case Info.hidl_discriminator.nr: return new CellInfoNr(ci, timeStamp); 390 default: return null; 391 } 392 } 393 394 /** @hide */ create(android.hardware.radio.V1_5.CellInfo ci, long timeStamp)395 public static CellInfo create(android.hardware.radio.V1_5.CellInfo ci, long timeStamp) { 396 if (ci == null) return null; 397 switch (ci.ratSpecificInfo.getDiscriminator()) { 398 case CellInfoRatSpecificInfo.hidl_discriminator.gsm: 399 return new CellInfoGsm(ci, timeStamp); 400 case CellInfoRatSpecificInfo.hidl_discriminator.cdma: 401 return new CellInfoCdma(ci, timeStamp); 402 case CellInfoRatSpecificInfo.hidl_discriminator.lte: 403 return new CellInfoLte(ci, timeStamp); 404 case CellInfoRatSpecificInfo.hidl_discriminator.wcdma: 405 return new CellInfoWcdma(ci, timeStamp); 406 case CellInfoRatSpecificInfo.hidl_discriminator.tdscdma: 407 return new CellInfoTdscdma(ci, timeStamp); 408 case CellInfoRatSpecificInfo.hidl_discriminator.nr: 409 return new CellInfoNr(ci, timeStamp); 410 default: return null; 411 } 412 } 413 } 414