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