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