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