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