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.IntRange; 20 import android.os.Parcel; 21 import android.os.Parcelable; 22 import android.os.PersistableBundle; 23 24 import com.android.internal.telephony.flags.Flags; 25 import com.android.telephony.Rlog; 26 27 import java.util.Objects; 28 29 /** 30 * Signal strength related information. 31 */ 32 public final class CellSignalStrengthCdma extends CellSignalStrength implements Parcelable { 33 34 private static final String LOG_TAG = "CellSignalStrengthCdma"; 35 private static final boolean DBG = false; 36 37 private int mCdmaDbm; // This value is the RSSI value 38 private int mCdmaEcio; // This value is the Ec/Io 39 private int mEvdoDbm; // This value is the EVDO RSSI value 40 private int mEvdoEcio; // This value is the EVDO Ec/Io 41 private int mEvdoSnr; // Valid values are 0-8. 8 is the highest signal to noise ratio 42 private int mLevel; 43 44 /** @hide */ CellSignalStrengthCdma()45 public CellSignalStrengthCdma() { 46 setDefaultValues(); 47 } 48 49 /** 50 * SignalStrength constructor for input from the HAL. 51 * 52 * Note that values received from the HAL require coersion to be compatible here. All values 53 * reported through IRadio are the negative of the actual values (which results in a positive 54 * input to this method. 55 * 56 * <p>Note that this HAL is inconsistent with UMTS-based radio techs as the value indicating 57 * that a field is unreported is negative, rather than a large(r) positive number. 58 * <p>Also note that to keep the public-facing methods of this class consistent with others, 59 * unreported values are coerced to {@link android.telephony.CellInfo#UNAVAILABLE UNAVAILABLE} 60 * rather than left as -1, which is a departure from SignalStrength, which is stuck with the 61 * values it currently reports. 62 * 63 * @param cdmaDbm CDMA signal strength value or CellInfo.UNAVAILABLE if invalid. 64 * @param cdmaEcio CDMA pilot/noise ratio or CellInfo.UNAVAILABLE if invalid. 65 * @param evdoDbm negative of the EvDO signal strength value or CellInfo.UNAVAILABLE if invalid. 66 * @param evdoEcio negative of the EvDO pilot/noise ratio or CellInfo.UNAVAILABLE if invalid. 67 * @param evdoSnr an SNR value 0..8 or CellInfo.UNVAILABLE if invalid. 68 * @hide 69 */ CellSignalStrengthCdma(int cdmaDbm, int cdmaEcio, int evdoDbm, int evdoEcio, int evdoSnr)70 public CellSignalStrengthCdma(int cdmaDbm, int cdmaEcio, int evdoDbm, int evdoEcio, 71 int evdoSnr) { 72 if (Flags.cleanupCdma()) { 73 setDefaultValues(); 74 } else { 75 mCdmaDbm = inRangeOrUnavailable(cdmaDbm, -120, 0); 76 mCdmaEcio = inRangeOrUnavailable(cdmaEcio, -160, 0); 77 mEvdoDbm = inRangeOrUnavailable(evdoDbm, -120, 0); 78 mEvdoEcio = inRangeOrUnavailable(evdoEcio, -160, 0); 79 mEvdoSnr = inRangeOrUnavailable(evdoSnr, 0, 8); 80 81 updateLevel(null, null); 82 } 83 } 84 85 /** @hide */ CellSignalStrengthCdma(CellSignalStrengthCdma s)86 public CellSignalStrengthCdma(CellSignalStrengthCdma s) { 87 copyFrom(s); 88 } 89 90 /** @hide */ copyFrom(CellSignalStrengthCdma s)91 protected void copyFrom(CellSignalStrengthCdma s) { 92 if (Flags.cleanupCdma()) { 93 setDefaultValues(); 94 return; 95 } 96 mCdmaDbm = s.mCdmaDbm; 97 mCdmaEcio = s.mCdmaEcio; 98 mEvdoDbm = s.mEvdoDbm; 99 mEvdoEcio = s.mEvdoEcio; 100 mEvdoSnr = s.mEvdoSnr; 101 mLevel = s.mLevel; 102 } 103 104 /** @hide */ 105 @Override copy()106 public CellSignalStrengthCdma copy() { 107 return new CellSignalStrengthCdma(this); 108 } 109 110 /** @hide */ 111 @Override setDefaultValues()112 public void setDefaultValues() { 113 mCdmaDbm = CellInfo.UNAVAILABLE; 114 mCdmaEcio = CellInfo.UNAVAILABLE; 115 mEvdoDbm = CellInfo.UNAVAILABLE; 116 mEvdoEcio = CellInfo.UNAVAILABLE; 117 mEvdoSnr = CellInfo.UNAVAILABLE; 118 mLevel = SIGNAL_STRENGTH_NONE_OR_UNKNOWN; 119 } 120 121 /** {@inheritDoc} */ 122 @Override 123 @IntRange(from = SIGNAL_STRENGTH_NONE_OR_UNKNOWN, to = SIGNAL_STRENGTH_GREAT) getLevel()124 public int getLevel() { 125 return mLevel; 126 } 127 128 /** @hide */ 129 @Override updateLevel(PersistableBundle cc, ServiceState ss)130 public void updateLevel(PersistableBundle cc, ServiceState ss) { 131 int cdmaLevel = getCdmaLevel(); 132 int evdoLevel = getEvdoLevel(); 133 if (evdoLevel == SIGNAL_STRENGTH_NONE_OR_UNKNOWN) { 134 /* We don't know evdo, use cdma */ 135 mLevel = getCdmaLevel(); 136 } else if (cdmaLevel == SIGNAL_STRENGTH_NONE_OR_UNKNOWN) { 137 /* We don't know cdma, use evdo */ 138 mLevel = getEvdoLevel(); 139 } else { 140 /* We know both, use the lowest level */ 141 mLevel = cdmaLevel < evdoLevel ? cdmaLevel : evdoLevel; 142 } 143 } 144 145 /** 146 * Get the 1xRTT Level in (Android) ASU. 147 * 148 * There is no standard definition of ASU for CDMA; however, Android defines it as the 149 * the lesser of the following two results (for 1xRTT): 150 * <table> 151 * <thead><tr><th>RSSI Range (dBm)</th><th>ASU Value</th></tr><thead> 152 * <tbody> 153 * <tr><td>-75..</td><td>16</td></tr> 154 * <tr><td>-82..-76</td><td>8</td></tr> 155 * <tr><td>-90..-83</td><td>4</td></tr> 156 * <tr><td>-95..-91</td><td>2</td></tr> 157 * <tr><td>-100..-96</td><td>1</td></tr> 158 * <tr><td>..-101</td><td>99</td></tr> 159 * </tbody> 160 * </table> 161 * <table> 162 * <thead><tr><th>Ec/Io Range (dB)</th><th>ASU Value</th></tr><thead> 163 * <tbody> 164 * <tr><td>-90..</td><td>16</td></tr> 165 * <tr><td>-100..-91</td><td>8</td></tr> 166 * <tr><td>-115..-101</td><td>4</td></tr> 167 * <tr><td>-130..-116</td><td>2</td></tr> 168 * <tr><td>--150..-131</td><td>1</td></tr> 169 * <tr><td>..-151</td><td>99</td></tr> 170 * </tbody> 171 * </table> 172 * @return 1xRTT Level in Android ASU {1,2,4,8,16,99} 173 */ 174 @Override 175 public int getAsuLevel() { 176 final int cdmaDbm = getCdmaDbm(); 177 final int cdmaEcio = getCdmaEcio(); 178 int cdmaAsuLevel; 179 int ecioAsuLevel; 180 181 if (cdmaDbm == CellInfo.UNAVAILABLE) cdmaAsuLevel = 99; 182 else if (cdmaDbm >= -75) cdmaAsuLevel = 16; 183 else if (cdmaDbm >= -82) cdmaAsuLevel = 8; 184 else if (cdmaDbm >= -90) cdmaAsuLevel = 4; 185 else if (cdmaDbm >= -95) cdmaAsuLevel = 2; 186 else if (cdmaDbm >= -100) cdmaAsuLevel = 1; 187 else cdmaAsuLevel = 99; 188 189 // Ec/Io are in dB*10 190 if (cdmaEcio == CellInfo.UNAVAILABLE) ecioAsuLevel = 99; 191 else if (cdmaEcio >= -90) ecioAsuLevel = 16; 192 else if (cdmaEcio >= -100) ecioAsuLevel = 8; 193 else if (cdmaEcio >= -115) ecioAsuLevel = 4; 194 else if (cdmaEcio >= -130) ecioAsuLevel = 2; 195 else if (cdmaEcio >= -150) ecioAsuLevel = 1; 196 else ecioAsuLevel = 99; 197 198 int level = (cdmaAsuLevel < ecioAsuLevel) ? cdmaAsuLevel : ecioAsuLevel; 199 if (DBG) log("getAsuLevel=" + level); 200 return level; 201 } 202 203 /** 204 * Get cdma as level 0..4 205 */ getCdmaLevel()206 public int getCdmaLevel() { 207 final int cdmaDbm = getCdmaDbm(); 208 final int cdmaEcio = getCdmaEcio(); 209 int levelDbm; 210 int levelEcio; 211 212 if (cdmaDbm == CellInfo.UNAVAILABLE) levelDbm = SIGNAL_STRENGTH_NONE_OR_UNKNOWN; 213 else if (cdmaDbm >= -75) levelDbm = SIGNAL_STRENGTH_GREAT; 214 else if (cdmaDbm >= -85) levelDbm = SIGNAL_STRENGTH_GOOD; 215 else if (cdmaDbm >= -95) levelDbm = SIGNAL_STRENGTH_MODERATE; 216 else if (cdmaDbm >= -100) levelDbm = SIGNAL_STRENGTH_POOR; 217 else levelDbm = SIGNAL_STRENGTH_NONE_OR_UNKNOWN; 218 219 // Ec/Io are in dB*10 220 if (cdmaEcio == CellInfo.UNAVAILABLE) levelEcio = SIGNAL_STRENGTH_NONE_OR_UNKNOWN; 221 else if (cdmaEcio >= -90) levelEcio = SIGNAL_STRENGTH_GREAT; 222 else if (cdmaEcio >= -110) levelEcio = SIGNAL_STRENGTH_GOOD; 223 else if (cdmaEcio >= -130) levelEcio = SIGNAL_STRENGTH_MODERATE; 224 else if (cdmaEcio >= -150) levelEcio = SIGNAL_STRENGTH_POOR; 225 else levelEcio = SIGNAL_STRENGTH_NONE_OR_UNKNOWN; 226 227 int level = (levelDbm < levelEcio) ? levelDbm : levelEcio; 228 if (DBG) log("getCdmaLevel=" + level); 229 return level; 230 } 231 232 /** 233 * Get Evdo as level 0..4 234 */ getEvdoLevel()235 public int getEvdoLevel() { 236 int evdoDbm = getEvdoDbm(); 237 int evdoSnr = getEvdoSnr(); 238 int levelEvdoDbm; 239 int levelEvdoSnr; 240 241 if (evdoDbm == CellInfo.UNAVAILABLE) levelEvdoDbm = SIGNAL_STRENGTH_NONE_OR_UNKNOWN; 242 else if (evdoDbm >= -65) levelEvdoDbm = SIGNAL_STRENGTH_GREAT; 243 else if (evdoDbm >= -75) levelEvdoDbm = SIGNAL_STRENGTH_GOOD; 244 else if (evdoDbm >= -90) levelEvdoDbm = SIGNAL_STRENGTH_MODERATE; 245 else if (evdoDbm >= -105) levelEvdoDbm = SIGNAL_STRENGTH_POOR; 246 else levelEvdoDbm = SIGNAL_STRENGTH_NONE_OR_UNKNOWN; 247 248 if (evdoSnr == CellInfo.UNAVAILABLE) levelEvdoSnr = SIGNAL_STRENGTH_NONE_OR_UNKNOWN; 249 else if (evdoSnr >= 7) levelEvdoSnr = SIGNAL_STRENGTH_GREAT; 250 else if (evdoSnr >= 5) levelEvdoSnr = SIGNAL_STRENGTH_GOOD; 251 else if (evdoSnr >= 3) levelEvdoSnr = SIGNAL_STRENGTH_MODERATE; 252 else if (evdoSnr >= 1) levelEvdoSnr = SIGNAL_STRENGTH_POOR; 253 else levelEvdoSnr = SIGNAL_STRENGTH_NONE_OR_UNKNOWN; 254 255 int level = (levelEvdoDbm < levelEvdoSnr) ? levelEvdoDbm : levelEvdoSnr; 256 if (DBG) log("getEvdoLevel=" + level); 257 return level; 258 } 259 260 /** 261 * Get the EVDO Level in (Android) ASU. 262 * 263 * There is no standard definition of ASU for CDMA; however, Android defines it as the 264 * the lesser of the following two results (for EVDO): 265 * <table> 266 * <thead><tr><th>RSSI Range (dBm)</th><th>ASU Value</th></tr><thead> 267 * <tbody> 268 * <tr><td>-65..</td><td>16</td></tr> 269 * <tr><td>-75..-66</td><td>8</td></tr> 270 * <tr><td>-85..-76</td><td>4</td></tr> 271 * <tr><td>-95..-86</td><td>2</td></tr> 272 * <tr><td>-105..-96</td><td>1</td></tr> 273 * <tr><td>..-106</td><td>99</td></tr> 274 * </tbody> 275 * </table> 276 * <table> 277 * <thead><tr><th>SNR Range (unitless)</th><th>ASU Value</th></tr><thead> 278 * <tbody> 279 * <tr><td>7..</td><td>16</td></tr> 280 * <tr><td>6</td><td>8</td></tr> 281 * <tr><td>5</td><td>4</td></tr> 282 * <tr><td>3..4</td><td>2</td></tr> 283 * <tr><td>1..2</td><td>1</td></tr> 284 * <tr><td>0</td><td>99</td></tr> 285 * </tbody> 286 * </table> 287 * 288 * @return EVDO Level in Android ASU {1,2,4,8,16,99} 289 * 290 * @hide 291 */ getEvdoAsuLevel()292 public int getEvdoAsuLevel() { 293 int evdoDbm = getEvdoDbm(); 294 int evdoSnr = getEvdoSnr(); 295 int levelEvdoDbm; 296 int levelEvdoSnr; 297 298 if (evdoDbm >= -65) levelEvdoDbm = 16; 299 else if (evdoDbm >= -75) levelEvdoDbm = 8; 300 else if (evdoDbm >= -85) levelEvdoDbm = 4; 301 else if (evdoDbm >= -95) levelEvdoDbm = 2; 302 else if (evdoDbm >= -105) levelEvdoDbm = 1; 303 else levelEvdoDbm = 99; 304 305 if (evdoSnr >= 7) levelEvdoSnr = 16; 306 else if (evdoSnr >= 6) levelEvdoSnr = 8; 307 else if (evdoSnr >= 5) levelEvdoSnr = 4; 308 else if (evdoSnr >= 3) levelEvdoSnr = 2; 309 else if (evdoSnr >= 1) levelEvdoSnr = 1; 310 else levelEvdoSnr = 99; 311 312 int level = (levelEvdoDbm < levelEvdoSnr) ? levelEvdoDbm : levelEvdoSnr; 313 if (DBG) log("getEvdoAsuLevel=" + level); 314 return level; 315 } 316 317 /** 318 * Get the signal strength as dBm 319 * 320 * @return min(CDMA RSSI, EVDO RSSI) of the measured cell. 321 */ 322 @Override getDbm()323 public int getDbm() { 324 int cdmaDbm = getCdmaDbm(); 325 int evdoDbm = getEvdoDbm(); 326 327 // Use the lower value to be conservative 328 return (cdmaDbm < evdoDbm) ? cdmaDbm : evdoDbm; 329 } 330 331 /** 332 * Get the CDMA RSSI value in dBm 333 */ getCdmaDbm()334 public int getCdmaDbm() { 335 return mCdmaDbm; 336 } 337 338 /** @hide */ setCdmaDbm(int cdmaDbm)339 public void setCdmaDbm(int cdmaDbm) { 340 mCdmaDbm = cdmaDbm; 341 } 342 343 /** 344 * Get the CDMA Ec/Io value in dB*10 345 */ getCdmaEcio()346 public int getCdmaEcio() { 347 return mCdmaEcio; 348 } 349 350 /** @hide */ setCdmaEcio(int cdmaEcio)351 public void setCdmaEcio(int cdmaEcio) { 352 mCdmaEcio = cdmaEcio; 353 } 354 355 /** 356 * Get the EVDO RSSI value in dBm 357 */ getEvdoDbm()358 public int getEvdoDbm() { 359 return mEvdoDbm; 360 } 361 362 /** @hide */ setEvdoDbm(int evdoDbm)363 public void setEvdoDbm(int evdoDbm) { 364 mEvdoDbm = evdoDbm; 365 } 366 367 /** 368 * Get the EVDO Ec/Io value in dB*10 369 */ getEvdoEcio()370 public int getEvdoEcio() { 371 return mEvdoEcio; 372 } 373 374 /** @hide */ setEvdoEcio(int evdoEcio)375 public void setEvdoEcio(int evdoEcio) { 376 mEvdoEcio = evdoEcio; 377 } 378 379 /** 380 * Get the signal to noise ratio. Valid values are 0-8. 8 is the highest. 381 */ getEvdoSnr()382 public int getEvdoSnr() { 383 return mEvdoSnr; 384 } 385 386 /** @hide */ setEvdoSnr(int evdoSnr)387 public void setEvdoSnr(int evdoSnr) { 388 mEvdoSnr = evdoSnr; 389 } 390 391 @Override hashCode()392 public int hashCode() { 393 return Objects.hash(mCdmaDbm, mCdmaEcio, mEvdoDbm, mEvdoEcio, mEvdoSnr, mLevel); 394 } 395 396 private static final CellSignalStrengthCdma sInvalid = new CellSignalStrengthCdma(); 397 398 /** @hide */ 399 @Override isValid()400 public boolean isValid() { 401 if (Flags.cleanupCdma()) return false; 402 return !this.equals(sInvalid); 403 } 404 405 @Override equals(Object o)406 public boolean equals (Object o) { 407 CellSignalStrengthCdma s; 408 if (!(o instanceof CellSignalStrengthCdma)) return false; 409 s = (CellSignalStrengthCdma) o; 410 411 return mCdmaDbm == s.mCdmaDbm 412 && mCdmaEcio == s.mCdmaEcio 413 && mEvdoDbm == s.mEvdoDbm 414 && mEvdoEcio == s.mEvdoEcio 415 && mEvdoSnr == s.mEvdoSnr 416 && mLevel == s.mLevel; 417 } 418 419 /** 420 * @return string representation. 421 */ 422 @Override toString()423 public String toString() { 424 return "CellSignalStrengthCdma:" 425 + " cdmaDbm=" + mCdmaDbm 426 + " cdmaEcio=" + mCdmaEcio 427 + " evdoDbm=" + mEvdoDbm 428 + " evdoEcio=" + mEvdoEcio 429 + " evdoSnr=" + mEvdoSnr 430 + " level=" + mLevel; 431 } 432 433 /** Implement the Parcelable interface */ 434 @Override writeToParcel(Parcel dest, int flags)435 public void writeToParcel(Parcel dest, int flags) { 436 if (DBG) log("writeToParcel(Parcel, int): " + toString()); 437 dest.writeInt(mCdmaDbm); 438 dest.writeInt(mCdmaEcio); 439 dest.writeInt(mEvdoDbm); 440 dest.writeInt(mEvdoEcio); 441 dest.writeInt(mEvdoSnr); 442 dest.writeInt(mLevel); 443 } 444 445 /** 446 * Construct a SignalStrength object from the given parcel 447 * where the TYPE_CDMA token is already been processed. 448 */ CellSignalStrengthCdma(Parcel in)449 private CellSignalStrengthCdma(Parcel in) { 450 // CdmaDbm, CdmaEcio, EvdoDbm and EvdoEcio are written into 451 // the parcel as positive values. 452 // Need to convert into negative values unless the value is invalid 453 mCdmaDbm = in.readInt(); 454 mCdmaEcio = in.readInt(); 455 mEvdoDbm = in.readInt(); 456 mEvdoEcio = in.readInt(); 457 mEvdoSnr = in.readInt(); 458 mLevel = in.readInt(); 459 460 if (Flags.cleanupCdma()) { 461 setDefaultValues(); 462 } else { 463 if (DBG) log("CellSignalStrengthCdma(Parcel): " + toString()); 464 } 465 } 466 467 /** Implement the Parcelable interface */ 468 @Override describeContents()469 public int describeContents() { 470 return 0; 471 } 472 473 /** Implement the Parcelable interface */ 474 @SuppressWarnings("hiding") 475 public static final @android.annotation.NonNull Parcelable.Creator<CellSignalStrengthCdma> CREATOR = 476 new Parcelable.Creator<CellSignalStrengthCdma>() { 477 @Override 478 public CellSignalStrengthCdma createFromParcel(Parcel in) { 479 return new CellSignalStrengthCdma(in); 480 } 481 482 @Override 483 public CellSignalStrengthCdma[] newArray(int size) { 484 return new CellSignalStrengthCdma[size]; 485 } 486 }; 487 488 /** 489 * log 490 */ log(String s)491 private static void log(String s) { 492 Rlog.w(LOG_TAG, s); 493 } 494 } 495