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.annotation.StringDef; 21 import android.annotation.UnsupportedAppUsage; 22 import android.os.Parcel; 23 import android.os.Parcelable; 24 import android.os.PersistableBundle; 25 import android.telephony.Rlog; 26 import android.text.TextUtils; 27 28 import java.lang.annotation.Retention; 29 import java.lang.annotation.RetentionPolicy; 30 import java.util.Objects; 31 32 /** 33 * Wcdma signal strength related information. 34 */ 35 public final class CellSignalStrengthWcdma extends CellSignalStrength implements Parcelable { 36 37 private static final String LOG_TAG = "CellSignalStrengthWcdma"; 38 private static final boolean DBG = false; 39 40 private static final int WCDMA_RSSI_MAX = -51; 41 private static final int WCDMA_RSSI_GREAT = -77; 42 private static final int WCDMA_RSSI_GOOD = -87; 43 private static final int WCDMA_RSSI_MODERATE = -97; 44 private static final int WCDMA_RSSI_POOR = -107; 45 private static final int WCDMA_RSSI_MIN = -113; 46 47 private static final int[] sRssiThresholds = new int[]{ 48 WCDMA_RSSI_POOR, WCDMA_RSSI_MODERATE, WCDMA_RSSI_GOOD, WCDMA_RSSI_GREAT}; 49 50 private static final int WCDMA_RSCP_MAX = -24; 51 private static final int WCDMA_RSCP_GREAT = -85; 52 private static final int WCDMA_RSCP_GOOD = -95; 53 private static final int WCDMA_RSCP_MODERATE = -105; 54 private static final int WCDMA_RSCP_POOR = -115; 55 private static final int WCDMA_RSCP_MIN = -120; 56 57 private static final int[] sRscpThresholds = new int[] { 58 WCDMA_RSCP_POOR, WCDMA_RSCP_MODERATE, WCDMA_RSCP_GOOD, WCDMA_RSCP_GREAT}; 59 60 // TODO: Because these are used as values in CarrierConfig, they should be exposed somehow. 61 /** @hide */ 62 @Retention(RetentionPolicy.SOURCE) 63 @StringDef({LEVEL_CALCULATION_METHOD_RSSI, LEVEL_CALCULATION_METHOD_RSCP}) 64 public @interface LevelCalculationMethod {} 65 /** @hide */ 66 public static final String LEVEL_CALCULATION_METHOD_RSSI = "rssi"; 67 /** @hide */ 68 public static final String LEVEL_CALCULATION_METHOD_RSCP = "rscp"; 69 70 // Default to RSSI for backwards compatibility with older devices 71 private static final String DEFAULT_LEVEL_CALCULATION_METHOD = LEVEL_CALCULATION_METHOD_RSSI; 72 73 private int mRssi; // in dBm [-113, 51] or CellInfo.UNAVAILABLE if unknown 74 75 @UnsupportedAppUsage 76 private int mBitErrorRate; // bit error rate (0-7, 99) as defined in TS 27.007 8.5 or 77 // CellInfo.UNAVAILABLE if unknown 78 private int mRscp; // in dBm [-120, -24] 79 private int mEcNo; // range -24, 1, CellInfo.UNAVAILABLE if unknown 80 private int mLevel; 81 82 /** @hide */ CellSignalStrengthWcdma()83 public CellSignalStrengthWcdma() { 84 setDefaultValues(); 85 } 86 87 /** @hide */ CellSignalStrengthWcdma(int rssi, int ber, int rscp, int ecno)88 public CellSignalStrengthWcdma(int rssi, int ber, int rscp, int ecno) { 89 mRssi = inRangeOrUnavailable(rssi, WCDMA_RSSI_MIN, WCDMA_RSSI_MAX); 90 mBitErrorRate = inRangeOrUnavailable(ber, 0, 7, 99); 91 mRscp = inRangeOrUnavailable(rscp, -120, -24); 92 mEcNo = inRangeOrUnavailable(ecno, -24, 1); 93 updateLevel(null, null); 94 } 95 96 /** @hide */ CellSignalStrengthWcdma(android.hardware.radio.V1_0.WcdmaSignalStrength wcdma)97 public CellSignalStrengthWcdma(android.hardware.radio.V1_0.WcdmaSignalStrength wcdma) { 98 // Convert from HAL values as part of construction. 99 this(getRssiDbmFromAsu(wcdma.signalStrength), wcdma.bitErrorRate, 100 CellInfo.UNAVAILABLE, CellInfo.UNAVAILABLE); 101 102 if (mRssi == CellInfo.UNAVAILABLE && mRscp == CellInfo.UNAVAILABLE) { 103 setDefaultValues(); 104 } 105 } 106 107 /** @hide */ CellSignalStrengthWcdma(android.hardware.radio.V1_2.WcdmaSignalStrength wcdma)108 public CellSignalStrengthWcdma(android.hardware.radio.V1_2.WcdmaSignalStrength wcdma) { 109 // Convert from HAL values as part of construction. 110 this(getRssiDbmFromAsu(wcdma.base.signalStrength), 111 wcdma.base.bitErrorRate, 112 getRscpDbmFromAsu(wcdma.rscp), 113 getEcNoDbFromAsu(wcdma.ecno)); 114 115 if (mRssi == CellInfo.UNAVAILABLE && mRscp == CellInfo.UNAVAILABLE) { 116 setDefaultValues(); 117 } 118 } 119 120 /** @hide */ CellSignalStrengthWcdma(CellSignalStrengthWcdma s)121 public CellSignalStrengthWcdma(CellSignalStrengthWcdma s) { 122 copyFrom(s); 123 } 124 125 /** @hide */ copyFrom(CellSignalStrengthWcdma s)126 protected void copyFrom(CellSignalStrengthWcdma s) { 127 mRssi = s.mRssi; 128 mBitErrorRate = s.mBitErrorRate; 129 mRscp = s.mRscp; 130 mEcNo = s.mEcNo; 131 mLevel = s.mLevel; 132 } 133 134 /** @hide */ 135 @Override copy()136 public CellSignalStrengthWcdma copy() { 137 return new CellSignalStrengthWcdma(this); 138 } 139 140 /** @hide */ 141 @Override setDefaultValues()142 public void setDefaultValues() { 143 mRssi = CellInfo.UNAVAILABLE; 144 mBitErrorRate = CellInfo.UNAVAILABLE; 145 mRscp = CellInfo.UNAVAILABLE; 146 mEcNo = CellInfo.UNAVAILABLE; 147 mLevel = SIGNAL_STRENGTH_NONE_OR_UNKNOWN; 148 } 149 150 /** {@inheritDoc} */ 151 @Override 152 @IntRange(from = SIGNAL_STRENGTH_NONE_OR_UNKNOWN, to = SIGNAL_STRENGTH_GREAT) getLevel()153 public int getLevel() { 154 return mLevel; 155 } 156 157 /** @hide */ 158 @Override updateLevel(PersistableBundle cc, ServiceState ss)159 public void updateLevel(PersistableBundle cc, ServiceState ss) { 160 String calcMethod; 161 int[] rscpThresholds; 162 163 if (cc == null) { 164 calcMethod = DEFAULT_LEVEL_CALCULATION_METHOD; 165 rscpThresholds = sRscpThresholds; 166 } else { 167 // TODO: abstract this entire thing into a series of functions 168 calcMethod = cc.getString( 169 CarrierConfigManager.KEY_WCDMA_DEFAULT_SIGNAL_STRENGTH_MEASUREMENT_STRING, 170 DEFAULT_LEVEL_CALCULATION_METHOD); 171 if (TextUtils.isEmpty(calcMethod)) calcMethod = DEFAULT_LEVEL_CALCULATION_METHOD; 172 rscpThresholds = cc.getIntArray( 173 CarrierConfigManager.KEY_WCDMA_RSCP_THRESHOLDS_INT_ARRAY); 174 if (rscpThresholds == null || rscpThresholds.length != NUM_SIGNAL_STRENGTH_THRESHOLDS) { 175 rscpThresholds = sRscpThresholds; 176 } 177 } 178 179 int level = NUM_SIGNAL_STRENGTH_THRESHOLDS; 180 switch (calcMethod) { 181 case LEVEL_CALCULATION_METHOD_RSCP: 182 if (mRscp < WCDMA_RSCP_MIN || mRscp > WCDMA_RSCP_MAX) { 183 mLevel = SIGNAL_STRENGTH_NONE_OR_UNKNOWN; 184 return; 185 } 186 while (level > 0 && mRscp < rscpThresholds[level - 1]) level--; 187 mLevel = level; 188 return; 189 default: 190 loge("Invalid Level Calculation Method for CellSignalStrengthWcdma = " 191 + calcMethod); 192 /** fall through */ 193 case LEVEL_CALCULATION_METHOD_RSSI: 194 if (mRssi < WCDMA_RSSI_MIN || mRssi > WCDMA_RSSI_MAX) { 195 mLevel = SIGNAL_STRENGTH_NONE_OR_UNKNOWN; 196 return; 197 } 198 while (level > 0 && mRssi < sRssiThresholds[level - 1]) level--; 199 mLevel = level; 200 return; 201 } 202 } 203 204 /** 205 * Get the RSCP as dBm value -120..-24dBm or {@link CellInfo#UNAVAILABLE UNAVAILABLE}. 206 */ 207 @Override getDbm()208 public int getDbm() { 209 if (mRscp != CellInfo.UNAVAILABLE) return mRscp; 210 return mRssi; 211 } 212 213 /** 214 * Get the RSCP in ASU. 215 * 216 * Asu is calculated based on 3GPP RSCP. Refer to 3GPP 27.007 (Ver 10.3.0) Sec 8.69 217 * 218 * @return RSCP in ASU 0..96, 255, or UNAVAILABLE 219 */ 220 @Override getAsuLevel()221 public int getAsuLevel() { 222 if (mRscp != CellInfo.UNAVAILABLE) return getAsuFromRscpDbm(mRscp); 223 // For historical reasons, if RSCP is unavailable, this API will very incorrectly return 224 // RSSI. This hackery will be removed when most devices are using Radio HAL 1.2+ 225 if (mRssi != CellInfo.UNAVAILABLE) return getAsuFromRssiDbm(mRssi); 226 return getAsuFromRscpDbm(CellInfo.UNAVAILABLE); 227 } 228 229 /** 230 * Get the RSSI as dBm 231 * 232 * @hide 233 */ getRssi()234 public int getRssi() { 235 return mRssi; 236 } 237 238 /** 239 * Get the RSCP as dBm 240 * 241 * @hide 242 */ getRscp()243 public int getRscp() { 244 return mRscp; 245 } 246 247 /** 248 * Get the Ec/No as dB 249 * 250 * @hide 251 */ getEcNo()252 public int getEcNo() { 253 return mEcNo; 254 } 255 256 /** 257 * Return the Bit Error Rate 258 * 259 * @returns the bit error rate (0-7, 99) as defined in TS 27.007 8.5 or UNAVAILABLE. 260 * @hide 261 */ getBitErrorRate()262 public int getBitErrorRate() { 263 return mBitErrorRate; 264 } 265 266 @Override hashCode()267 public int hashCode() { 268 return Objects.hash(mRssi, mBitErrorRate, mRscp, mEcNo, mLevel); 269 } 270 271 private static final CellSignalStrengthWcdma sInvalid = new CellSignalStrengthWcdma(); 272 273 /** @hide */ 274 @Override isValid()275 public boolean isValid() { 276 return !this.equals(sInvalid); 277 } 278 279 @Override equals(Object o)280 public boolean equals(Object o) { 281 if (!(o instanceof CellSignalStrengthWcdma)) return false; 282 CellSignalStrengthWcdma s = (CellSignalStrengthWcdma) o; 283 284 return mRssi == s.mRssi 285 && mBitErrorRate == s.mBitErrorRate 286 && mRscp == s.mRscp 287 && mEcNo == s.mEcNo 288 && mLevel == s.mLevel; 289 } 290 291 /** 292 * @return string representation. 293 */ 294 @Override toString()295 public String toString() { 296 return "CellSignalStrengthWcdma:" 297 + " ss=" + mRssi 298 + " ber=" + mBitErrorRate 299 + " rscp=" + mRscp 300 + " ecno=" + mEcNo 301 + " level=" + mLevel; 302 } 303 304 /** Implement the Parcelable interface */ 305 @Override writeToParcel(Parcel dest, int flags)306 public void writeToParcel(Parcel dest, int flags) { 307 if (DBG) log("writeToParcel(Parcel, int): " + toString()); 308 dest.writeInt(mRssi); 309 dest.writeInt(mBitErrorRate); 310 dest.writeInt(mRscp); 311 dest.writeInt(mEcNo); 312 dest.writeInt(mLevel); 313 } 314 315 /** 316 * Construct a SignalStrength object from the given parcel 317 * where the token is already been processed. 318 */ CellSignalStrengthWcdma(Parcel in)319 private CellSignalStrengthWcdma(Parcel in) { 320 mRssi = in.readInt(); 321 mBitErrorRate = in.readInt(); 322 mRscp = in.readInt(); 323 mEcNo = in.readInt(); 324 mLevel = in.readInt(); 325 if (DBG) log("CellSignalStrengthWcdma(Parcel): " + toString()); 326 } 327 328 /** Implement the Parcelable interface */ 329 @Override describeContents()330 public int describeContents() { 331 return 0; 332 } 333 334 /** Implement the Parcelable interface */ 335 @SuppressWarnings("hiding") 336 public static final @android.annotation.NonNull Parcelable.Creator<CellSignalStrengthWcdma> CREATOR = 337 new Parcelable.Creator<CellSignalStrengthWcdma>() { 338 @Override 339 public CellSignalStrengthWcdma createFromParcel(Parcel in) { 340 return new CellSignalStrengthWcdma(in); 341 } 342 343 @Override 344 public CellSignalStrengthWcdma[] newArray(int size) { 345 return new CellSignalStrengthWcdma[size]; 346 } 347 }; 348 349 /** 350 * log warning 351 */ log(String s)352 private static void log(String s) { 353 Rlog.w(LOG_TAG, s); 354 } 355 356 /** 357 * log error 358 */ loge(String s)359 private static void loge(String s) { 360 Rlog.e(LOG_TAG, s); 361 } 362 } 363