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(CellSignalStrengthWcdma s)98     public CellSignalStrengthWcdma(CellSignalStrengthWcdma s) {
99         copyFrom(s);
100     }
101 
102     /** @hide */
copyFrom(CellSignalStrengthWcdma s)103     protected void copyFrom(CellSignalStrengthWcdma s) {
104         mRssi = s.mRssi;
105         mBitErrorRate = s.mBitErrorRate;
106         mRscp = s.mRscp;
107         mEcNo = s.mEcNo;
108         mLevel = s.mLevel;
109     }
110 
111     /** @hide */
112     @Override
copy()113     public CellSignalStrengthWcdma copy() {
114         return new CellSignalStrengthWcdma(this);
115     }
116 
117     /** @hide */
118     @Override
setDefaultValues()119     public void setDefaultValues() {
120         mRssi = CellInfo.UNAVAILABLE;
121         mBitErrorRate = CellInfo.UNAVAILABLE;
122         mRscp = CellInfo.UNAVAILABLE;
123         mEcNo = CellInfo.UNAVAILABLE;
124         mLevel = SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
125     }
126 
127     /** {@inheritDoc} */
128     @Override
129     @IntRange(from = SIGNAL_STRENGTH_NONE_OR_UNKNOWN, to = SIGNAL_STRENGTH_GREAT)
getLevel()130     public int getLevel() {
131         return mLevel;
132     }
133 
134     /** @hide */
135     @Override
updateLevel(PersistableBundle cc, ServiceState ss)136     public void updateLevel(PersistableBundle cc, ServiceState ss) {
137         String calcMethod;
138         int[] rscpThresholds;
139 
140         if (cc == null) {
141             calcMethod = DEFAULT_LEVEL_CALCULATION_METHOD;
142             rscpThresholds = sRscpThresholds;
143         } else {
144             // TODO: abstract this entire thing into a series of functions
145             calcMethod = cc.getString(
146                     CarrierConfigManager.KEY_WCDMA_DEFAULT_SIGNAL_STRENGTH_MEASUREMENT_STRING,
147                     DEFAULT_LEVEL_CALCULATION_METHOD);
148             if (TextUtils.isEmpty(calcMethod)) calcMethod = DEFAULT_LEVEL_CALCULATION_METHOD;
149             rscpThresholds = cc.getIntArray(
150                     CarrierConfigManager.KEY_WCDMA_RSCP_THRESHOLDS_INT_ARRAY);
151             if (rscpThresholds == null || rscpThresholds.length != NUM_SIGNAL_STRENGTH_THRESHOLDS) {
152                 rscpThresholds = sRscpThresholds;
153             }
154         }
155 
156         int level = NUM_SIGNAL_STRENGTH_THRESHOLDS;
157         switch (calcMethod) {
158             case LEVEL_CALCULATION_METHOD_RSCP:
159                 if (mRscp < WCDMA_RSCP_MIN || mRscp > WCDMA_RSCP_MAX) {
160                     mLevel = SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
161                     return;
162                 }
163                 while (level > 0 && mRscp < rscpThresholds[level - 1]) level--;
164                 mLevel = level;
165                 return;
166             default:
167                 loge("Invalid Level Calculation Method for CellSignalStrengthWcdma = "
168                         + calcMethod);
169                 /** fall through */
170             case LEVEL_CALCULATION_METHOD_RSSI:
171                 if (mRssi < WCDMA_RSSI_MIN || mRssi > WCDMA_RSSI_MAX) {
172                     mLevel = SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
173                     return;
174                 }
175                 while (level > 0 && mRssi < sRssiThresholds[level - 1]) level--;
176                 mLevel = level;
177                 return;
178         }
179     }
180 
181     /**
182      * Get the RSCP as dBm value -120..-24dBm or {@link CellInfo#UNAVAILABLE UNAVAILABLE}.
183      */
184     @Override
getDbm()185     public int getDbm() {
186         if (mRscp != CellInfo.UNAVAILABLE) return mRscp;
187         return mRssi;
188     }
189 
190     /**
191      * Get the RSCP in ASU.
192      *
193      * Asu is calculated based on 3GPP RSCP. Refer to 3GPP 27.007 (Ver 10.3.0) Sec 8.69
194      *
195      * @return RSCP in ASU 0..96, 255, or UNAVAILABLE
196      */
197     @Override
getAsuLevel()198     public int getAsuLevel() {
199         if (mRscp != CellInfo.UNAVAILABLE) return getAsuFromRscpDbm(mRscp);
200         // For historical reasons, if RSCP is unavailable, this API will very incorrectly return
201         // RSSI. This hackery will be removed when most devices are using Radio HAL 1.2+
202         if (mRssi != CellInfo.UNAVAILABLE) return getAsuFromRssiDbm(mRssi);
203         return getAsuFromRscpDbm(CellInfo.UNAVAILABLE);
204     }
205 
206     /**
207      * Get the RSSI as dBm
208      *
209      * @hide
210      */
getRssi()211     public int getRssi() {
212         return mRssi;
213     }
214 
215     /**
216      * Get the RSCP as dBm
217      *
218      * @hide
219      */
getRscp()220     public int getRscp() {
221         return mRscp;
222     }
223 
224     /**
225      * Get the Ec/No (Energy per chip over the noise spectral density) as dB.
226      *
227      * Reference: TS 25.133 Section 9.1.2.3
228      *
229      * @return the Ec/No of the measured cell in the range [-24, 1] or
230      * {@link android.telephony.CellInfo#UNAVAILABLE UNAVAILABLE} if unavailable
231      */
getEcNo()232     public int getEcNo() {
233         return mEcNo;
234     }
235 
236     /**
237      * Return the Bit Error Rate
238      *
239      * @returns the bit error rate (0-7, 99) as defined in TS 27.007 8.5 or UNAVAILABLE.
240      * @hide
241      */
getBitErrorRate()242     public int getBitErrorRate() {
243         return mBitErrorRate;
244     }
245 
246     @Override
hashCode()247     public int hashCode() {
248         return Objects.hash(mRssi, mBitErrorRate, mRscp, mEcNo, mLevel);
249     }
250 
251     private static final CellSignalStrengthWcdma sInvalid = new CellSignalStrengthWcdma();
252 
253     /** @hide */
254     @Override
isValid()255     public boolean isValid() {
256         return !this.equals(sInvalid);
257     }
258 
259     @Override
equals(Object o)260     public boolean equals(Object o) {
261         if (!(o instanceof CellSignalStrengthWcdma)) return false;
262         CellSignalStrengthWcdma s = (CellSignalStrengthWcdma) o;
263 
264         return mRssi == s.mRssi
265                 && mBitErrorRate == s.mBitErrorRate
266                 && mRscp == s.mRscp
267                 && mEcNo == s.mEcNo
268                 && mLevel == s.mLevel;
269     }
270 
271     /**
272      * @return string representation.
273      */
274     @Override
toString()275     public String toString() {
276         return "CellSignalStrengthWcdma:"
277                 + " ss=" + mRssi
278                 + " ber=" + mBitErrorRate
279                 + " rscp=" + mRscp
280                 + " ecno=" + mEcNo
281                 + " level=" + mLevel;
282     }
283 
284     /** Implement the Parcelable interface */
285     @Override
writeToParcel(Parcel dest, int flags)286     public void writeToParcel(Parcel dest, int flags) {
287         if (DBG) log("writeToParcel(Parcel, int): " + toString());
288         dest.writeInt(mRssi);
289         dest.writeInt(mBitErrorRate);
290         dest.writeInt(mRscp);
291         dest.writeInt(mEcNo);
292         dest.writeInt(mLevel);
293     }
294 
295     /**
296      * Construct a SignalStrength object from the given parcel
297      * where the token is already been processed.
298      */
CellSignalStrengthWcdma(Parcel in)299     private CellSignalStrengthWcdma(Parcel in) {
300         mRssi = in.readInt();
301         mBitErrorRate = in.readInt();
302         mRscp = in.readInt();
303         mEcNo = in.readInt();
304         mLevel = in.readInt();
305         if (DBG) log("CellSignalStrengthWcdma(Parcel): " + toString());
306     }
307 
308     /** Implement the Parcelable interface */
309     @Override
describeContents()310     public int describeContents() {
311         return 0;
312     }
313 
314     /** Implement the Parcelable interface */
315     @SuppressWarnings("hiding")
316     public static final @android.annotation.NonNull Parcelable.Creator<CellSignalStrengthWcdma> CREATOR =
317             new Parcelable.Creator<CellSignalStrengthWcdma>() {
318         @Override
319         public CellSignalStrengthWcdma createFromParcel(Parcel in) {
320             return new CellSignalStrengthWcdma(in);
321         }
322 
323         @Override
324         public CellSignalStrengthWcdma[] newArray(int size) {
325             return new CellSignalStrengthWcdma[size];
326         }
327     };
328 
329     /**
330      * log warning
331      */
log(String s)332     private static void log(String s) {
333         Rlog.w(LOG_TAG, s);
334     }
335 
336     /**
337      * log error
338      */
loge(String s)339     private static void loge(String s) {
340         Rlog.e(LOG_TAG, s);
341     }
342 }
343