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.Parcel;
20import android.os.Parcelable;
21import android.telephony.Rlog;
22
23/**
24 * GSM signal strength related information.
25 */
26public final class CellSignalStrengthGsm extends CellSignalStrength implements Parcelable {
27
28    private static final String LOG_TAG = "CellSignalStrengthGsm";
29    private static final boolean DBG = false;
30
31    private static final int GSM_SIGNAL_STRENGTH_GREAT = 12;
32    private static final int GSM_SIGNAL_STRENGTH_GOOD = 8;
33    private static final int GSM_SIGNAL_STRENGTH_MODERATE = 5;
34
35    private int mSignalStrength; // Valid values are (0-31, 99) as defined in TS 27.007 8.5
36    private int mBitErrorRate;   // bit error rate (0-7, 99) as defined in TS 27.007 8.5
37    private int mTimingAdvance;
38
39    /**
40     * Empty constructor
41     *
42     * @hide
43     */
44    public CellSignalStrengthGsm() {
45        setDefaultValues();
46    }
47
48    /**
49     * Constructor
50     *
51     * @hide
52     */
53    public CellSignalStrengthGsm(int ss, int ber) {
54        initialize(ss, ber);
55    }
56
57    /**
58     * Copy constructors
59     *
60     * @param s Source SignalStrength
61     *
62     * @hide
63     */
64    public CellSignalStrengthGsm(CellSignalStrengthGsm s) {
65        copyFrom(s);
66    }
67
68    /**
69     * Initialize all the values
70     *
71     * @param ss SignalStrength as ASU value
72     * @param ber is Bit Error Rate
73     *
74     * @hide
75     */
76    public void initialize(int ss, int ber) {
77        mSignalStrength = ss;
78        mBitErrorRate = ber;
79        mTimingAdvance = Integer.MAX_VALUE;
80    }
81
82    /**
83     * Initialize all the values
84     *
85     * @param ss SignalStrength as ASU value
86     * @param ber is Bit Error Rate
87     * @param ta timing advance
88     *
89     * @hide
90     */
91    public void initialize(int ss, int ber, int ta) {
92        mSignalStrength = ss;
93        mBitErrorRate = ber;
94        mTimingAdvance = ta;
95    }
96
97    /**
98     * @hide
99     */
100    protected void copyFrom(CellSignalStrengthGsm s) {
101        mSignalStrength = s.mSignalStrength;
102        mBitErrorRate = s.mBitErrorRate;
103        mTimingAdvance = s.mTimingAdvance;
104    }
105
106    /**
107     * @hide
108     */
109    @Override
110    public CellSignalStrengthGsm copy() {
111        return new CellSignalStrengthGsm(this);
112    }
113
114    /** @hide */
115    @Override
116    public void setDefaultValues() {
117        mSignalStrength = Integer.MAX_VALUE;
118        mBitErrorRate = Integer.MAX_VALUE;
119        mTimingAdvance = Integer.MAX_VALUE;
120    }
121
122    /**
123     * Get signal level as an int from 0..4
124     */
125    @Override
126    public int getLevel() {
127        int level;
128
129        // ASU ranges from 0 to 31 - TS 27.007 Sec 8.5
130        // asu = 0 (-113dB or less) is very weak
131        // signal, its better to show 0 bars to the user in such cases.
132        // asu = 99 is a special case, where the signal strength is unknown.
133        int asu = mSignalStrength;
134        if (asu <= 2 || asu == 99) level = SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
135        else if (asu >= GSM_SIGNAL_STRENGTH_GREAT) level = SIGNAL_STRENGTH_GREAT;
136        else if (asu >= GSM_SIGNAL_STRENGTH_GOOD)  level = SIGNAL_STRENGTH_GOOD;
137        else if (asu >= GSM_SIGNAL_STRENGTH_MODERATE)  level = SIGNAL_STRENGTH_MODERATE;
138        else level = SIGNAL_STRENGTH_POOR;
139        if (DBG) log("getLevel=" + level);
140        return level;
141    }
142
143    /**
144     * Get the GSM timing advance between 0..219 symbols (normally 0..63).
145     * Integer.MAX_VALUE is reported when there is no RR connection.
146     * Refer to 3GPP 45.010 Sec 5.8
147     * @return the current GSM timing advance, if available.
148     */
149    public int getTimingAdvance() {
150        return mTimingAdvance;
151    }
152
153    /**
154     * Get the signal strength as dBm
155     */
156    @Override
157    public int getDbm() {
158        int dBm;
159
160        int level = mSignalStrength;
161        int asu = (level == 99 ? Integer.MAX_VALUE : level);
162        if (asu != Integer.MAX_VALUE) {
163            dBm = -113 + (2 * asu);
164        } else {
165            dBm = Integer.MAX_VALUE;
166        }
167        if (DBG) log("getDbm=" + dBm);
168        return dBm;
169    }
170
171    /**
172     * Get the signal level as an asu value between 0..31, 99 is unknown
173     * Asu is calculated based on 3GPP RSRP. Refer to 3GPP 27.007 (Ver 10.3.0) Sec 8.69
174     */
175    @Override
176    public int getAsuLevel() {
177        // ASU ranges from 0 to 31 - TS 27.007 Sec 8.5
178        // asu = 0 (-113dB or less) is very weak
179        // signal, its better to show 0 bars to the user in such cases.
180        // asu = 99 is a special case, where the signal strength is unknown.
181        int level = mSignalStrength;
182        if (DBG) log("getAsuLevel=" + level);
183        return level;
184    }
185
186    @Override
187    public int hashCode() {
188        int primeNum = 31;
189        return (mSignalStrength * primeNum) + (mBitErrorRate * primeNum);
190    }
191
192    @Override
193    public boolean equals (Object o) {
194        CellSignalStrengthGsm s;
195
196        try {
197            s = (CellSignalStrengthGsm) o;
198        } catch (ClassCastException ex) {
199            return false;
200        }
201
202        if (o == null) {
203            return false;
204        }
205
206        return mSignalStrength == s.mSignalStrength && mBitErrorRate == s.mBitErrorRate &&
207                        s.mTimingAdvance == mTimingAdvance;
208    }
209
210    /**
211     * @return string representation.
212     */
213    @Override
214    public String toString() {
215        return "CellSignalStrengthGsm:"
216                + " ss=" + mSignalStrength
217                + " ber=" + mBitErrorRate
218                + " mTa=" + mTimingAdvance;
219    }
220
221    /** Implement the Parcelable interface */
222    @Override
223    public void writeToParcel(Parcel dest, int flags) {
224        if (DBG) log("writeToParcel(Parcel, int): " + toString());
225        dest.writeInt(mSignalStrength);
226        dest.writeInt(mBitErrorRate);
227        dest.writeInt(mTimingAdvance);
228    }
229
230    /**
231     * Construct a SignalStrength object from the given parcel
232     * where the token is already been processed.
233     */
234    private CellSignalStrengthGsm(Parcel in) {
235        mSignalStrength = in.readInt();
236        mBitErrorRate = in.readInt();
237        mTimingAdvance = in.readInt();
238        if (DBG) log("CellSignalStrengthGsm(Parcel): " + toString());
239    }
240
241    /** Implement the Parcelable interface */
242    @Override
243    public int describeContents() {
244        return 0;
245    }
246
247    /** Implement the Parcelable interface */
248    @SuppressWarnings("hiding")
249    public static final Parcelable.Creator<CellSignalStrengthGsm> CREATOR =
250            new Parcelable.Creator<CellSignalStrengthGsm>() {
251        @Override
252        public CellSignalStrengthGsm createFromParcel(Parcel in) {
253            return new CellSignalStrengthGsm(in);
254        }
255
256        @Override
257        public CellSignalStrengthGsm[] newArray(int size) {
258            return new CellSignalStrengthGsm[size];
259        }
260    };
261
262    /**
263     * log
264     */
265    private static void log(String s) {
266        Rlog.w(LOG_TAG, s);
267    }
268}
269