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