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
17package android.telephony;
18
19import android.os.Bundle;
20import android.os.Parcel;
21import android.os.Parcelable;
22import android.telephony.Rlog;
23
24/**
25 * Contains phone signal strength related information.
26 */
27public class SignalStrength implements Parcelable {
28
29    private static final String LOG_TAG = "SignalStrength";
30    private static final boolean DBG = false;
31
32    /** @hide */
33    public static final int SIGNAL_STRENGTH_NONE_OR_UNKNOWN = 0;
34    /** @hide */
35    public static final int SIGNAL_STRENGTH_POOR = 1;
36    /** @hide */
37    public static final int SIGNAL_STRENGTH_MODERATE = 2;
38    /** @hide */
39    public static final int SIGNAL_STRENGTH_GOOD = 3;
40    /** @hide */
41    public static final int SIGNAL_STRENGTH_GREAT = 4;
42    /** @hide */
43    public static final int NUM_SIGNAL_STRENGTH_BINS = 5;
44    /** @hide */
45    public static final String[] SIGNAL_STRENGTH_NAMES = {
46        "none", "poor", "moderate", "good", "great"
47    };
48
49    /** @hide */
50    //Use int max, as -1 is a valid value in signal strength
51    public static final int INVALID = 0x7FFFFFFF;
52
53    private int mGsmSignalStrength; // Valid values are (0-31, 99) as defined in TS 27.007 8.5
54    private int mGsmBitErrorRate;   // bit error rate (0-7, 99) as defined in TS 27.007 8.5
55    private int mCdmaDbm;   // This value is the RSSI value
56    private int mCdmaEcio;  // This value is the Ec/Io
57    private int mEvdoDbm;   // This value is the EVDO RSSI value
58    private int mEvdoEcio;  // This value is the EVDO Ec/Io
59    private int mEvdoSnr;   // Valid values are 0-8.  8 is the highest signal to noise ratio
60    private int mLteSignalStrength;
61    private int mLteRsrp;
62    private int mLteRsrq;
63    private int mLteRssnr;
64    private int mLteCqi;
65
66    private boolean isGsm; // This value is set by the ServiceStateTracker onSignalStrengthResult
67
68    /**
69     * Create a new SignalStrength from a intent notifier Bundle
70     *
71     * This method is used by PhoneStateIntentReceiver and maybe by
72     * external applications.
73     *
74     * @param m Bundle from intent notifier
75     * @return newly created SignalStrength
76     *
77     * @hide
78     */
79    public static SignalStrength newFromBundle(Bundle m) {
80        SignalStrength ret;
81        ret = new SignalStrength();
82        ret.setFromNotifierBundle(m);
83        return ret;
84    }
85
86    /**
87     * Empty constructor
88     *
89     * @hide
90     */
91    public SignalStrength() {
92        mGsmSignalStrength = 99;
93        mGsmBitErrorRate = -1;
94        mCdmaDbm = -1;
95        mCdmaEcio = -1;
96        mEvdoDbm = -1;
97        mEvdoEcio = -1;
98        mEvdoSnr = -1;
99        mLteSignalStrength = 99;
100        mLteRsrp = INVALID;
101        mLteRsrq = INVALID;
102        mLteRssnr = INVALID;
103        mLteCqi = INVALID;
104        isGsm = true;
105    }
106
107    /**
108     * This constructor is used to create SignalStrength with default
109     * values and set the isGsmFlag with the value passed in the input
110     *
111     * @param gsmFlag true if Gsm Phone,false if Cdma phone
112     * @return newly created SignalStrength
113     * @hide
114     */
115    public SignalStrength(boolean gsmFlag) {
116        mGsmSignalStrength = 99;
117        mGsmBitErrorRate = -1;
118        mCdmaDbm = -1;
119        mCdmaEcio = -1;
120        mEvdoDbm = -1;
121        mEvdoEcio = -1;
122        mEvdoSnr = -1;
123        mLteSignalStrength = 99;
124        mLteRsrp = INVALID;
125        mLteRsrq = INVALID;
126        mLteRssnr = INVALID;
127        mLteCqi = INVALID;
128        isGsm = gsmFlag;
129    }
130
131    /**
132     * Constructor
133     *
134     * @hide
135     */
136    public SignalStrength(int gsmSignalStrength, int gsmBitErrorRate,
137            int cdmaDbm, int cdmaEcio,
138            int evdoDbm, int evdoEcio, int evdoSnr,
139            int lteSignalStrength, int lteRsrp, int lteRsrq, int lteRssnr, int lteCqi,
140            boolean gsmFlag) {
141        initialize(gsmSignalStrength, gsmBitErrorRate, cdmaDbm, cdmaEcio,
142                evdoDbm, evdoEcio, evdoSnr, lteSignalStrength, lteRsrp,
143                lteRsrq, lteRssnr, lteCqi, gsmFlag);
144    }
145
146    /**
147     * Constructor
148     *
149     * @hide
150     */
151    public SignalStrength(int gsmSignalStrength, int gsmBitErrorRate,
152            int cdmaDbm, int cdmaEcio,
153            int evdoDbm, int evdoEcio, int evdoSnr,
154            boolean gsmFlag) {
155        initialize(gsmSignalStrength, gsmBitErrorRate, cdmaDbm, cdmaEcio,
156                evdoDbm, evdoEcio, evdoSnr, 99, INVALID,
157                INVALID, INVALID, INVALID, gsmFlag);
158    }
159
160    /**
161     * Copy constructors
162     *
163     * @param s Source SignalStrength
164     *
165     * @hide
166     */
167    public SignalStrength(SignalStrength s) {
168        copyFrom(s);
169    }
170
171    /**
172     * Initialize gsm/cdma values, sets lte values to defaults.
173     *
174     * @param gsmSignalStrength
175     * @param gsmBitErrorRate
176     * @param cdmaDbm
177     * @param cdmaEcio
178     * @param evdoDbm
179     * @param evdoEcio
180     * @param evdoSnr
181     * @param gsm
182     *
183     * @hide
184     */
185    public void initialize(int gsmSignalStrength, int gsmBitErrorRate,
186            int cdmaDbm, int cdmaEcio,
187            int evdoDbm, int evdoEcio, int evdoSnr,
188            boolean gsm) {
189        initialize(gsmSignalStrength, gsmBitErrorRate, cdmaDbm, cdmaEcio,
190                evdoDbm, evdoEcio, evdoSnr, 99, INVALID,
191                INVALID, INVALID, INVALID, gsm);
192    }
193
194    /**
195     * Initialize all the values
196     *
197     * @param gsmSignalStrength
198     * @param gsmBitErrorRate
199     * @param cdmaDbm
200     * @param cdmaEcio
201     * @param evdoDbm
202     * @param evdoEcio
203     * @param evdoSnr
204     * @param lteSignalStrength
205     * @param lteRsrp
206     * @param lteRsrq
207     * @param lteRssnr
208     * @param lteCqi
209     * @param gsm
210     *
211     * @hide
212     */
213    public void initialize(int gsmSignalStrength, int gsmBitErrorRate,
214            int cdmaDbm, int cdmaEcio,
215            int evdoDbm, int evdoEcio, int evdoSnr,
216            int lteSignalStrength, int lteRsrp, int lteRsrq, int lteRssnr, int lteCqi,
217            boolean gsm) {
218        mGsmSignalStrength = gsmSignalStrength;
219        mGsmBitErrorRate = gsmBitErrorRate;
220        mCdmaDbm = cdmaDbm;
221        mCdmaEcio = cdmaEcio;
222        mEvdoDbm = evdoDbm;
223        mEvdoEcio = evdoEcio;
224        mEvdoSnr = evdoSnr;
225        mLteSignalStrength = lteSignalStrength;
226        mLteRsrp = lteRsrp;
227        mLteRsrq = lteRsrq;
228        mLteRssnr = lteRssnr;
229        mLteCqi = lteCqi;
230        isGsm = gsm;
231        if (DBG) log("initialize: " + toString());
232    }
233
234    /**
235     * @hide
236     */
237    protected void copyFrom(SignalStrength s) {
238        mGsmSignalStrength = s.mGsmSignalStrength;
239        mGsmBitErrorRate = s.mGsmBitErrorRate;
240        mCdmaDbm = s.mCdmaDbm;
241        mCdmaEcio = s.mCdmaEcio;
242        mEvdoDbm = s.mEvdoDbm;
243        mEvdoEcio = s.mEvdoEcio;
244        mEvdoSnr = s.mEvdoSnr;
245        mLteSignalStrength = s.mLteSignalStrength;
246        mLteRsrp = s.mLteRsrp;
247        mLteRsrq = s.mLteRsrq;
248        mLteRssnr = s.mLteRssnr;
249        mLteCqi = s.mLteCqi;
250        isGsm = s.isGsm;
251    }
252
253    /**
254     * Construct a SignalStrength object from the given parcel.
255     *
256     * @hide
257     */
258    public SignalStrength(Parcel in) {
259        if (DBG) log("Size of signalstrength parcel:" + in.dataSize());
260
261        mGsmSignalStrength = in.readInt();
262        mGsmBitErrorRate = in.readInt();
263        mCdmaDbm = in.readInt();
264        mCdmaEcio = in.readInt();
265        mEvdoDbm = in.readInt();
266        mEvdoEcio = in.readInt();
267        mEvdoSnr = in.readInt();
268        mLteSignalStrength = in.readInt();
269        mLteRsrp = in.readInt();
270        mLteRsrq = in.readInt();
271        mLteRssnr = in.readInt();
272        mLteCqi = in.readInt();
273        isGsm = (in.readInt() != 0);
274    }
275
276    /**
277     * Make a SignalStrength object from the given parcel as passed up by
278     * the ril which does not have isGsm. isGsm will be changed by ServiceStateTracker
279     * so the default is a don't care.
280     *
281     * @hide
282     */
283    public static SignalStrength makeSignalStrengthFromRilParcel(Parcel in) {
284        if (DBG) log("Size of signalstrength parcel:" + in.dataSize());
285
286        SignalStrength ss = new SignalStrength();
287        ss.mGsmSignalStrength = in.readInt();
288        ss.mGsmBitErrorRate = in.readInt();
289        ss.mCdmaDbm = in.readInt();
290        ss.mCdmaEcio = in.readInt();
291        ss.mEvdoDbm = in.readInt();
292        ss.mEvdoEcio = in.readInt();
293        ss.mEvdoSnr = in.readInt();
294        ss.mLteSignalStrength = in.readInt();
295        ss.mLteRsrp = in.readInt();
296        ss.mLteRsrq = in.readInt();
297        ss.mLteRssnr = in.readInt();
298        ss.mLteCqi = in.readInt();
299
300        return ss;
301    }
302
303    /**
304     * {@link Parcelable#writeToParcel}
305     */
306    public void writeToParcel(Parcel out, int flags) {
307        out.writeInt(mGsmSignalStrength);
308        out.writeInt(mGsmBitErrorRate);
309        out.writeInt(mCdmaDbm);
310        out.writeInt(mCdmaEcio);
311        out.writeInt(mEvdoDbm);
312        out.writeInt(mEvdoEcio);
313        out.writeInt(mEvdoSnr);
314        out.writeInt(mLteSignalStrength);
315        out.writeInt(mLteRsrp);
316        out.writeInt(mLteRsrq);
317        out.writeInt(mLteRssnr);
318        out.writeInt(mLteCqi);
319        out.writeInt(isGsm ? 1 : 0);
320    }
321
322    /**
323     * {@link Parcelable#describeContents}
324     */
325    public int describeContents() {
326        return 0;
327    }
328
329    /**
330     * {@link Parcelable.Creator}
331     *
332     * @hide
333     */
334    public static final Parcelable.Creator<SignalStrength> CREATOR = new Parcelable.Creator() {
335        public SignalStrength createFromParcel(Parcel in) {
336            return new SignalStrength(in);
337        }
338
339        public SignalStrength[] newArray(int size) {
340            return new SignalStrength[size];
341        }
342    };
343
344    /**
345     * Validate the individual signal strength fields as per the range
346     * specified in ril.h
347     * Set to invalid any field that is not in the valid range
348     * Cdma, evdo, lte rsrp & rsrq values are sign converted
349     * when received from ril interface
350     *
351     * @return
352     *      Valid values for all signalstrength fields
353     * @hide
354     */
355    public void validateInput() {
356        if (DBG) log("Signal before validate=" + this);
357        // TS 27.007 8.5
358        mGsmSignalStrength = mGsmSignalStrength >= 0 ? mGsmSignalStrength : 99;
359        // BER no change;
360
361        mCdmaDbm = mCdmaDbm > 0 ? -mCdmaDbm : -120;
362        mCdmaEcio = (mCdmaEcio > 0) ? -mCdmaEcio : -160;
363
364        mEvdoDbm = (mEvdoDbm > 0) ? -mEvdoDbm : -120;
365        mEvdoEcio = (mEvdoEcio >= 0) ? -mEvdoEcio : -1;
366        mEvdoSnr = ((mEvdoSnr > 0) && (mEvdoSnr <= 8)) ? mEvdoSnr : -1;
367
368        // TS 36.214 Physical Layer Section 5.1.3, TS 36.331 RRC
369        mLteSignalStrength = (mLteSignalStrength >= 0) ? mLteSignalStrength : 99;
370        mLteRsrp = ((mLteRsrp >= 44) && (mLteRsrp <= 140)) ? -mLteRsrp : SignalStrength.INVALID;
371        mLteRsrq = ((mLteRsrq >= 3) && (mLteRsrq <= 20)) ? -mLteRsrq : SignalStrength.INVALID;
372        mLteRssnr = ((mLteRssnr >= -200) && (mLteRssnr <= 300)) ? mLteRssnr
373                : SignalStrength.INVALID;
374        // Cqi no change
375        if (DBG) log("Signal after validate=" + this);
376    }
377
378    /**
379     * @param true - Gsm, Lte phones
380     *        false - Cdma phones
381     *
382     * Used by voice phone to set the isGsm
383     *        flag
384     * @hide
385     */
386    public void setGsm(boolean gsmFlag) {
387        isGsm = gsmFlag;
388    }
389
390    /**
391     * Get the GSM Signal Strength, valid values are (0-31, 99) as defined in TS
392     * 27.007 8.5
393     */
394    public int getGsmSignalStrength() {
395        return this.mGsmSignalStrength;
396    }
397
398    /**
399     * Get the GSM bit error rate (0-7, 99) as defined in TS 27.007 8.5
400     */
401    public int getGsmBitErrorRate() {
402        return this.mGsmBitErrorRate;
403    }
404
405    /**
406     * Get the CDMA RSSI value in dBm
407     */
408    public int getCdmaDbm() {
409        return this.mCdmaDbm;
410    }
411
412    /**
413     * Get the CDMA Ec/Io value in dB*10
414     */
415    public int getCdmaEcio() {
416        return this.mCdmaEcio;
417    }
418
419    /**
420     * Get the EVDO RSSI value in dBm
421     */
422    public int getEvdoDbm() {
423        return this.mEvdoDbm;
424    }
425
426    /**
427     * Get the EVDO Ec/Io value in dB*10
428     */
429    public int getEvdoEcio() {
430        return this.mEvdoEcio;
431    }
432
433    /**
434     * Get the signal to noise ratio. Valid values are 0-8. 8 is the highest.
435     */
436    public int getEvdoSnr() {
437        return this.mEvdoSnr;
438    }
439
440    /** @hide */
441    public int getLteSignalStrength() {
442        return mLteSignalStrength;
443    }
444
445    /** @hide */
446    public int getLteRsrp() {
447        return mLteRsrp;
448    }
449
450    /** @hide */
451    public int getLteRsrq() {
452        return mLteRsrq;
453    }
454
455    /** @hide */
456    public int getLteRssnr() {
457        return mLteRssnr;
458    }
459
460    /** @hide */
461    public int getLteCqi() {
462        return mLteCqi;
463    }
464
465    /**
466     * Get signal level as an int from 0..4
467     *
468     * @hide
469     */
470    public int getLevel() {
471        int level;
472
473        if (isGsm) {
474            level = getLteLevel();
475            if (level == SIGNAL_STRENGTH_NONE_OR_UNKNOWN) {
476                level = getGsmLevel();
477            }
478        } else {
479            int cdmaLevel = getCdmaLevel();
480            int evdoLevel = getEvdoLevel();
481            if (evdoLevel == SIGNAL_STRENGTH_NONE_OR_UNKNOWN) {
482                /* We don't know evdo, use cdma */
483                level = cdmaLevel;
484            } else if (cdmaLevel == SIGNAL_STRENGTH_NONE_OR_UNKNOWN) {
485                /* We don't know cdma, use evdo */
486                level = evdoLevel;
487            } else {
488                /* We know both, use the lowest level */
489                level = cdmaLevel < evdoLevel ? cdmaLevel : evdoLevel;
490            }
491        }
492        if (DBG) log("getLevel=" + level);
493        return level;
494    }
495
496    /**
497     * Get the signal level as an asu value between 0..31, 99 is unknown
498     *
499     * @hide
500     */
501    public int getAsuLevel() {
502        int asuLevel;
503        if (isGsm) {
504            if (getLteLevel() == SIGNAL_STRENGTH_NONE_OR_UNKNOWN) {
505                asuLevel = getGsmAsuLevel();
506            } else {
507                asuLevel = getLteAsuLevel();
508            }
509        } else {
510            int cdmaAsuLevel = getCdmaAsuLevel();
511            int evdoAsuLevel = getEvdoAsuLevel();
512            if (evdoAsuLevel == 0) {
513                /* We don't know evdo use, cdma */
514                asuLevel = cdmaAsuLevel;
515            } else if (cdmaAsuLevel == 0) {
516                /* We don't know cdma use, evdo */
517                asuLevel = evdoAsuLevel;
518            } else {
519                /* We know both, use the lowest level */
520                asuLevel = cdmaAsuLevel < evdoAsuLevel ? cdmaAsuLevel : evdoAsuLevel;
521            }
522        }
523        if (DBG) log("getAsuLevel=" + asuLevel);
524        return asuLevel;
525    }
526
527    /**
528     * Get the signal strength as dBm
529     *
530     * @hide
531     */
532    public int getDbm() {
533        int dBm;
534
535        if(isGsm()) {
536            if (getLteLevel() == SIGNAL_STRENGTH_NONE_OR_UNKNOWN) {
537                dBm = getGsmDbm();
538            } else {
539                dBm = getLteDbm();
540            }
541        } else {
542            int cdmaDbm = getCdmaDbm();
543            int evdoDbm = getEvdoDbm();
544
545            return (evdoDbm == -120) ? cdmaDbm : ((cdmaDbm == -120) ? evdoDbm
546                    : (cdmaDbm < evdoDbm ? cdmaDbm : evdoDbm));
547        }
548        if (DBG) log("getDbm=" + dBm);
549        return dBm;
550    }
551
552    /**
553     * Get Gsm signal strength as dBm
554     *
555     * @hide
556     */
557    public int getGsmDbm() {
558        int dBm;
559
560        int gsmSignalStrength = getGsmSignalStrength();
561        int asu = (gsmSignalStrength == 99 ? -1 : gsmSignalStrength);
562        if (asu != -1) {
563            dBm = -113 + (2 * asu);
564        } else {
565            dBm = -1;
566        }
567        if (DBG) log("getGsmDbm=" + dBm);
568        return dBm;
569    }
570
571    /**
572     * Get gsm as level 0..4
573     *
574     * @hide
575     */
576    public int getGsmLevel() {
577        int level;
578
579        // ASU ranges from 0 to 31 - TS 27.007 Sec 8.5
580        // asu = 0 (-113dB or less) is very weak
581        // signal, its better to show 0 bars to the user in such cases.
582        // asu = 99 is a special case, where the signal strength is unknown.
583        int asu = getGsmSignalStrength();
584        if (asu <= 2 || asu == 99) level = SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
585        else if (asu >= 12) level = SIGNAL_STRENGTH_GREAT;
586        else if (asu >= 8)  level = SIGNAL_STRENGTH_GOOD;
587        else if (asu >= 5)  level = SIGNAL_STRENGTH_MODERATE;
588        else level = SIGNAL_STRENGTH_POOR;
589        if (DBG) log("getGsmLevel=" + level);
590        return level;
591    }
592
593    /**
594     * Get the gsm signal level as an asu value between 0..31, 99 is unknown
595     *
596     * @hide
597     */
598    public int getGsmAsuLevel() {
599        // ASU ranges from 0 to 31 - TS 27.007 Sec 8.5
600        // asu = 0 (-113dB or less) is very weak
601        // signal, its better to show 0 bars to the user in such cases.
602        // asu = 99 is a special case, where the signal strength is unknown.
603        int level = getGsmSignalStrength();
604        if (DBG) log("getGsmAsuLevel=" + level);
605        return level;
606    }
607
608    /**
609     * Get cdma as level 0..4
610     *
611     * @hide
612     */
613    public int getCdmaLevel() {
614        final int cdmaDbm = getCdmaDbm();
615        final int cdmaEcio = getCdmaEcio();
616        int levelDbm;
617        int levelEcio;
618
619        if (cdmaDbm >= -75) levelDbm = SIGNAL_STRENGTH_GREAT;
620        else if (cdmaDbm >= -85) levelDbm = SIGNAL_STRENGTH_GOOD;
621        else if (cdmaDbm >= -95) levelDbm = SIGNAL_STRENGTH_MODERATE;
622        else if (cdmaDbm >= -100) levelDbm = SIGNAL_STRENGTH_POOR;
623        else levelDbm = SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
624
625        // Ec/Io are in dB*10
626        if (cdmaEcio >= -90) levelEcio = SIGNAL_STRENGTH_GREAT;
627        else if (cdmaEcio >= -110) levelEcio = SIGNAL_STRENGTH_GOOD;
628        else if (cdmaEcio >= -130) levelEcio = SIGNAL_STRENGTH_MODERATE;
629        else if (cdmaEcio >= -150) levelEcio = SIGNAL_STRENGTH_POOR;
630        else levelEcio = SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
631
632        int level = (levelDbm < levelEcio) ? levelDbm : levelEcio;
633        if (DBG) log("getCdmaLevel=" + level);
634        return level;
635    }
636
637    /**
638     * Get the cdma signal level as an asu value between 0..31, 99 is unknown
639     *
640     * @hide
641     */
642    public int getCdmaAsuLevel() {
643        final int cdmaDbm = getCdmaDbm();
644        final int cdmaEcio = getCdmaEcio();
645        int cdmaAsuLevel;
646        int ecioAsuLevel;
647
648        if (cdmaDbm >= -75) cdmaAsuLevel = 16;
649        else if (cdmaDbm >= -82) cdmaAsuLevel = 8;
650        else if (cdmaDbm >= -90) cdmaAsuLevel = 4;
651        else if (cdmaDbm >= -95) cdmaAsuLevel = 2;
652        else if (cdmaDbm >= -100) cdmaAsuLevel = 1;
653        else cdmaAsuLevel = 99;
654
655        // Ec/Io are in dB*10
656        if (cdmaEcio >= -90) ecioAsuLevel = 16;
657        else if (cdmaEcio >= -100) ecioAsuLevel = 8;
658        else if (cdmaEcio >= -115) ecioAsuLevel = 4;
659        else if (cdmaEcio >= -130) ecioAsuLevel = 2;
660        else if (cdmaEcio >= -150) ecioAsuLevel = 1;
661        else ecioAsuLevel = 99;
662
663        int level = (cdmaAsuLevel < ecioAsuLevel) ? cdmaAsuLevel : ecioAsuLevel;
664        if (DBG) log("getCdmaAsuLevel=" + level);
665        return level;
666    }
667
668    /**
669     * Get Evdo as level 0..4
670     *
671     * @hide
672     */
673    public int getEvdoLevel() {
674        int evdoDbm = getEvdoDbm();
675        int evdoSnr = getEvdoSnr();
676        int levelEvdoDbm;
677        int levelEvdoSnr;
678
679        if (evdoDbm >= -65) levelEvdoDbm = SIGNAL_STRENGTH_GREAT;
680        else if (evdoDbm >= -75) levelEvdoDbm = SIGNAL_STRENGTH_GOOD;
681        else if (evdoDbm >= -90) levelEvdoDbm = SIGNAL_STRENGTH_MODERATE;
682        else if (evdoDbm >= -105) levelEvdoDbm = SIGNAL_STRENGTH_POOR;
683        else levelEvdoDbm = SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
684
685        if (evdoSnr >= 7) levelEvdoSnr = SIGNAL_STRENGTH_GREAT;
686        else if (evdoSnr >= 5) levelEvdoSnr = SIGNAL_STRENGTH_GOOD;
687        else if (evdoSnr >= 3) levelEvdoSnr = SIGNAL_STRENGTH_MODERATE;
688        else if (evdoSnr >= 1) levelEvdoSnr = SIGNAL_STRENGTH_POOR;
689        else levelEvdoSnr = SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
690
691        int level = (levelEvdoDbm < levelEvdoSnr) ? levelEvdoDbm : levelEvdoSnr;
692        if (DBG) log("getEvdoLevel=" + level);
693        return level;
694    }
695
696    /**
697     * Get the evdo signal level as an asu value between 0..31, 99 is unknown
698     *
699     * @hide
700     */
701    public int getEvdoAsuLevel() {
702        int evdoDbm = getEvdoDbm();
703        int evdoSnr = getEvdoSnr();
704        int levelEvdoDbm;
705        int levelEvdoSnr;
706
707        if (evdoDbm >= -65) levelEvdoDbm = 16;
708        else if (evdoDbm >= -75) levelEvdoDbm = 8;
709        else if (evdoDbm >= -85) levelEvdoDbm = 4;
710        else if (evdoDbm >= -95) levelEvdoDbm = 2;
711        else if (evdoDbm >= -105) levelEvdoDbm = 1;
712        else levelEvdoDbm = 99;
713
714        if (evdoSnr >= 7) levelEvdoSnr = 16;
715        else if (evdoSnr >= 6) levelEvdoSnr = 8;
716        else if (evdoSnr >= 5) levelEvdoSnr = 4;
717        else if (evdoSnr >= 3) levelEvdoSnr = 2;
718        else if (evdoSnr >= 1) levelEvdoSnr = 1;
719        else levelEvdoSnr = 99;
720
721        int level = (levelEvdoDbm < levelEvdoSnr) ? levelEvdoDbm : levelEvdoSnr;
722        if (DBG) log("getEvdoAsuLevel=" + level);
723        return level;
724    }
725
726    /**
727     * Get LTE as dBm
728     *
729     * @hide
730     */
731    public int getLteDbm() {
732        return mLteRsrp;
733    }
734
735    /**
736     * Get LTE as level 0..4
737     *
738     * @hide
739     */
740    public int getLteLevel() {
741        /*
742         * TS 36.214 Physical Layer Section 5.1.3 TS 36.331 RRC RSSI = received
743         * signal + noise RSRP = reference signal dBm RSRQ = quality of signal
744         * dB= Number of Resource blocksxRSRP/RSSI SNR = gain=signal/noise ratio
745         * = -10log P1/P2 dB
746         */
747        int rssiIconLevel = SIGNAL_STRENGTH_NONE_OR_UNKNOWN, rsrpIconLevel = -1, snrIconLevel = -1;
748
749        if (mLteRsrp > -44) rsrpIconLevel = -1;
750        else if (mLteRsrp >= -85) rsrpIconLevel = SIGNAL_STRENGTH_GREAT;
751        else if (mLteRsrp >= -95) rsrpIconLevel = SIGNAL_STRENGTH_GOOD;
752        else if (mLteRsrp >= -105) rsrpIconLevel = SIGNAL_STRENGTH_MODERATE;
753        else if (mLteRsrp >= -115) rsrpIconLevel = SIGNAL_STRENGTH_POOR;
754        else if (mLteRsrp >= -140) rsrpIconLevel = SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
755
756        /*
757         * Values are -200 dB to +300 (SNR*10dB) RS_SNR >= 13.0 dB =>4 bars 4.5
758         * dB <= RS_SNR < 13.0 dB => 3 bars 1.0 dB <= RS_SNR < 4.5 dB => 2 bars
759         * -3.0 dB <= RS_SNR < 1.0 dB 1 bar RS_SNR < -3.0 dB/No Service Antenna
760         * Icon Only
761         */
762        if (mLteRssnr > 300) snrIconLevel = -1;
763        else if (mLteRssnr >= 130) snrIconLevel = SIGNAL_STRENGTH_GREAT;
764        else if (mLteRssnr >= 45) snrIconLevel = SIGNAL_STRENGTH_GOOD;
765        else if (mLteRssnr >= 10) snrIconLevel = SIGNAL_STRENGTH_MODERATE;
766        else if (mLteRssnr >= -30) snrIconLevel = SIGNAL_STRENGTH_POOR;
767        else if (mLteRssnr >= -200)
768            snrIconLevel = SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
769
770        if (DBG) log("getLTELevel - rsrp:" + mLteRsrp + " snr:" + mLteRssnr + " rsrpIconLevel:"
771                + rsrpIconLevel + " snrIconLevel:" + snrIconLevel);
772
773        /* Choose a measurement type to use for notification */
774        if (snrIconLevel != -1 && rsrpIconLevel != -1) {
775            /*
776             * The number of bars displayed shall be the smaller of the bars
777             * associated with LTE RSRP and the bars associated with the LTE
778             * RS_SNR
779             */
780            return (rsrpIconLevel < snrIconLevel ? rsrpIconLevel : snrIconLevel);
781        }
782
783        if (snrIconLevel != -1) return snrIconLevel;
784
785        if (rsrpIconLevel != -1) return rsrpIconLevel;
786
787        /* Valid values are (0-63, 99) as defined in TS 36.331 */
788        if (mLteSignalStrength > 63) rssiIconLevel = SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
789        else if (mLteSignalStrength >= 12) rssiIconLevel = SIGNAL_STRENGTH_GREAT;
790        else if (mLteSignalStrength >= 8) rssiIconLevel = SIGNAL_STRENGTH_GOOD;
791        else if (mLteSignalStrength >= 5) rssiIconLevel = SIGNAL_STRENGTH_MODERATE;
792        else if (mLteSignalStrength >= 0) rssiIconLevel = SIGNAL_STRENGTH_POOR;
793        if (DBG) log("getLTELevel - rssi:" + mLteSignalStrength + " rssiIconLevel:"
794                + rssiIconLevel);
795        return rssiIconLevel;
796
797    }
798    /**
799     * Get the LTE signal level as an asu value between 0..97, 99 is unknown
800     * Asu is calculated based on 3GPP RSRP. Refer to 3GPP 27.007 (Ver 10.3.0) Sec 8.69
801     *
802     * @hide
803     */
804    public int getLteAsuLevel() {
805        int lteAsuLevel = 99;
806        int lteDbm = getLteDbm();
807        /*
808         * 3GPP 27.007 (Ver 10.3.0) Sec 8.69
809         * 0   -140 dBm or less
810         * 1   -139 dBm
811         * 2...96  -138... -44 dBm
812         * 97  -43 dBm or greater
813         * 255 not known or not detectable
814         */
815        /*
816         * validateInput will always give a valid range between -140 t0 -44 as
817         * per ril.h. so RSRP >= -43 & <-140 will fall under asu level 255
818         * and not 97 or 0
819         */
820        if (lteDbm == SignalStrength.INVALID) lteAsuLevel = 255;
821        else lteAsuLevel = lteDbm + 140;
822        if (DBG) log("Lte Asu level: "+lteAsuLevel);
823        return lteAsuLevel;
824    }
825
826    /**
827     * @return true if this is for GSM
828     */
829    public boolean isGsm() {
830        return this.isGsm;
831    }
832
833    /**
834     * @return hash code
835     */
836    @Override
837    public int hashCode() {
838        int primeNum = 31;
839        return ((mGsmSignalStrength * primeNum)
840                + (mGsmBitErrorRate * primeNum)
841                + (mCdmaDbm * primeNum) + (mCdmaEcio * primeNum)
842                + (mEvdoDbm * primeNum) + (mEvdoEcio * primeNum) + (mEvdoSnr * primeNum)
843                + (mLteSignalStrength * primeNum) + (mLteRsrp * primeNum)
844                + (mLteRsrq * primeNum) + (mLteRssnr * primeNum) + (mLteCqi * primeNum)
845                + (isGsm ? 1 : 0));
846    }
847
848    /**
849     * @return true if the signal strengths are the same
850     */
851    @Override
852    public boolean equals (Object o) {
853        SignalStrength s;
854
855        try {
856            s = (SignalStrength) o;
857        } catch (ClassCastException ex) {
858            return false;
859        }
860
861        if (o == null) {
862            return false;
863        }
864
865        return (mGsmSignalStrength == s.mGsmSignalStrength
866                && mGsmBitErrorRate == s.mGsmBitErrorRate
867                && mCdmaDbm == s.mCdmaDbm
868                && mCdmaEcio == s.mCdmaEcio
869                && mEvdoDbm == s.mEvdoDbm
870                && mEvdoEcio == s.mEvdoEcio
871                && mEvdoSnr == s.mEvdoSnr
872                && mLteSignalStrength == s.mLteSignalStrength
873                && mLteRsrp == s.mLteRsrp
874                && mLteRsrq == s.mLteRsrq
875                && mLteRssnr == s.mLteRssnr
876                && mLteCqi == s.mLteCqi
877                && isGsm == s.isGsm);
878    }
879
880    /**
881     * @return string representation.
882     */
883    @Override
884    public String toString() {
885        return ("SignalStrength:"
886                + " " + mGsmSignalStrength
887                + " " + mGsmBitErrorRate
888                + " " + mCdmaDbm
889                + " " + mCdmaEcio
890                + " " + mEvdoDbm
891                + " " + mEvdoEcio
892                + " " + mEvdoSnr
893                + " " + mLteSignalStrength
894                + " " + mLteRsrp
895                + " " + mLteRsrq
896                + " " + mLteRssnr
897                + " " + mLteCqi
898                + " " + (isGsm ? "gsm|lte" : "cdma"));
899    }
900
901    /**
902     * Set SignalStrength based on intent notifier map
903     *
904     * @param m intent notifier map
905     * @hide
906     */
907    private void setFromNotifierBundle(Bundle m) {
908        mGsmSignalStrength = m.getInt("GsmSignalStrength");
909        mGsmBitErrorRate = m.getInt("GsmBitErrorRate");
910        mCdmaDbm = m.getInt("CdmaDbm");
911        mCdmaEcio = m.getInt("CdmaEcio");
912        mEvdoDbm = m.getInt("EvdoDbm");
913        mEvdoEcio = m.getInt("EvdoEcio");
914        mEvdoSnr = m.getInt("EvdoSnr");
915        mLteSignalStrength = m.getInt("LteSignalStrength");
916        mLteRsrp = m.getInt("LteRsrp");
917        mLteRsrq = m.getInt("LteRsrq");
918        mLteRssnr = m.getInt("LteRssnr");
919        mLteCqi = m.getInt("LteCqi");
920        isGsm = m.getBoolean("isGsm");
921    }
922
923    /**
924     * Set intent notifier Bundle based on SignalStrength
925     *
926     * @param m intent notifier Bundle
927     * @hide
928     */
929    public void fillInNotifierBundle(Bundle m) {
930        m.putInt("GsmSignalStrength", mGsmSignalStrength);
931        m.putInt("GsmBitErrorRate", mGsmBitErrorRate);
932        m.putInt("CdmaDbm", mCdmaDbm);
933        m.putInt("CdmaEcio", mCdmaEcio);
934        m.putInt("EvdoDbm", mEvdoDbm);
935        m.putInt("EvdoEcio", mEvdoEcio);
936        m.putInt("EvdoSnr", mEvdoSnr);
937        m.putInt("LteSignalStrength", mLteSignalStrength);
938        m.putInt("LteRsrp", mLteRsrp);
939        m.putInt("LteRsrq", mLteRsrq);
940        m.putInt("LteRssnr", mLteRssnr);
941        m.putInt("LteCqi", mLteCqi);
942        m.putBoolean("isGsm", Boolean.valueOf(isGsm));
943    }
944
945    /**
946     * log
947     */
948    private static void log(String s) {
949        Rlog.w(LOG_TAG, s);
950    }
951}
952