CdmaLteServiceStateTracker.java revision d6bcfd1cd081b9fe553976a0191a814b929c583e
1/*
2 * Copyright (C) 2008 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 com.android.internal.telephony.cdma;
18
19import com.android.internal.telephony.TelephonyProperties;
20import com.android.internal.telephony.MccTable;
21import com.android.internal.telephony.EventLogTags;
22import com.android.internal.telephony.RILConstants;
23
24import android.telephony.SignalStrength;
25import android.telephony.ServiceState;
26import android.telephony.cdma.CdmaCellLocation;
27import android.os.AsyncResult;
28import android.os.Message;
29
30
31import android.util.Log;
32import android.util.EventLog;
33
34import com.android.internal.telephony.gsm.GsmDataConnectionTracker;
35
36public class CdmaLteServiceStateTracker extends CdmaServiceStateTracker {
37    CDMALTEPhone mCdmaLtePhone;
38
39    private ServiceState  mLteSS;  // The last LTE state from Voice Registration
40
41    public CdmaLteServiceStateTracker(CDMALTEPhone phone) {
42        super(phone);
43        cm.registerForSIMReady(this, EVENT_SIM_READY, null);
44        mCdmaLtePhone = phone;
45
46        mLteSS = new ServiceState();
47        if (DBG) log("CdmaLteServiceStateTracker Constructors");
48    }
49
50    @Override
51    public void dispose() {
52        cm.unregisterForSIMReady(this);
53        super.dispose();
54    }
55
56    @Override
57    public void handleMessage(Message msg) {
58        AsyncResult ar;
59        int[] ints;
60        String[] strings;
61        switch (msg.what) {
62        case EVENT_POLL_STATE_GPRS:
63            if (DBG) log("handleMessage EVENT_POLL_STATE_GPRS");
64            ar = (AsyncResult)msg.obj;
65            handlePollStateResult(msg.what, ar);
66            break;
67        case EVENT_SIM_READY:
68            if (DBG) log("handleMessage EVENT_SIM_READY");
69            isSubscriptionFromRuim = false;
70            cm.getCDMASubscription( obtainMessage(EVENT_POLL_STATE_CDMA_SUBSCRIPTION));
71            pollState();
72            // Signal strength polling stops when radio is off.
73            queueNextSignalStrengthPoll();
74            break;
75        default:
76            super.handleMessage(msg);
77        }
78    }
79
80    /**
81     * Set the cdmaSS for EVENT_POLL_STATE_REGISTRATION_CDMA
82     */
83    @Override
84    protected void setCdmaTechnology(int radioTechnology) {
85        // Called on voice registration state response.
86        // Just record new CDMA radio technology
87        newSS.setRadioTechnology(radioTechnology);
88    }
89
90    /**
91     * Handle the result of one of the pollState()-related requests
92     */
93    @Override
94    protected void handlePollStateResultMessage(int what, AsyncResult ar) {
95        if (what == EVENT_POLL_STATE_GPRS) {
96            if (DBG) log("handlePollStateResultMessage: EVENT_POLL_STATE_GPRS");
97            String states[] = (String[])ar.result;
98
99            int type = 0;
100            int regState = -1;
101            if (states.length > 0) {
102                try {
103                    regState = Integer.parseInt(states[0]);
104
105                    // states[3] (if present) is the current radio technology
106                    if (states.length >= 4 && states[3] != null) {
107                        type = Integer.parseInt(states[3]);
108                    }
109                } catch (NumberFormatException ex) {
110                    loge("handlePollStateResultMessage: error parsing GprsRegistrationState: "
111                                    + ex);
112                }
113            }
114
115            // Not sure if this is needed in CDMALTE phone.
116            // mDataRoaming = regCodeIsRoaming(regState);
117            mLteSS.setRadioTechnology(type);
118            mLteSS.setState(regCodeToServiceState(regState));
119        } else {
120            super.handlePollStateResultMessage(what, ar);
121        }
122    }
123
124    @Override
125    protected void setSignalStrengthDefaultValues() {
126        mSignalStrength = new SignalStrength(99, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, false);
127    }
128
129    @Override
130    protected void pollState() {
131        pollingContext = new int[1];
132        pollingContext[0] = 0;
133
134        switch (cm.getRadioState()) {
135            case RADIO_UNAVAILABLE:
136                newSS.setStateOutOfService();
137                newCellLoc.setStateInvalid();
138                setSignalStrengthDefaultValues();
139                mGotCountryCode = false;
140
141                pollStateDone();
142                break;
143
144            case RADIO_OFF:
145                newSS.setStateOff();
146                newCellLoc.setStateInvalid();
147                setSignalStrengthDefaultValues();
148                mGotCountryCode = false;
149
150                pollStateDone();
151                break;
152
153            default:
154                // Issue all poll-related commands at once, then count
155                // down the responses which are allowed to arrive
156                // out-of-order.
157
158                pollingContext[0]++;
159                // RIL_REQUEST_OPERATOR is necessary for CDMA
160                cm.getOperator(obtainMessage(EVENT_POLL_STATE_OPERATOR_CDMA, pollingContext));
161
162                pollingContext[0]++;
163                // RIL_REQUEST_VOICE_REGISTRATION_STATE is necessary for CDMA
164                cm.getVoiceRegistrationState(obtainMessage(EVENT_POLL_STATE_REGISTRATION_CDMA,
165                        pollingContext));
166
167                int networkMode = android.provider.Settings.Secure.getInt(phone.getContext()
168                        .getContentResolver(),
169                        android.provider.Settings.Secure.PREFERRED_NETWORK_MODE,
170                        RILConstants.PREFERRED_NETWORK_MODE);
171                if (DBG) log("pollState: network mode here is = " + networkMode);
172                if ((networkMode == RILConstants.NETWORK_MODE_GLOBAL)
173                        || (networkMode == RILConstants.NETWORK_MODE_LTE_ONLY)) {
174                    pollingContext[0]++;
175                    // RIL_REQUEST_DATA_REGISTRATION_STATE
176                    cm.getDataRegistrationState(obtainMessage(EVENT_POLL_STATE_GPRS,
177                                                pollingContext));
178                }
179                break;
180        }
181    }
182
183    @Override
184    protected void pollStateDone() {
185        // determine data NetworkType from both LET and CDMA SS
186        if (mLteSS.getState() == ServiceState.STATE_IN_SERVICE) {
187            //in LTE service
188            newNetworkType = mLteSS.getRadioTechnology();
189            mNewDataConnectionState = mLteSS.getState();
190            newSS.setRadioTechnology(newNetworkType);
191            log("pollStateDone LTE/eHRPD STATE_IN_SERVICE newNetworkType = " + newNetworkType);
192        } else {
193            // LTE out of service, get CDMA Service State
194            newNetworkType = newSS.getRadioTechnology();
195            mNewDataConnectionState = radioTechnologyToDataServiceState(newNetworkType);
196            log("pollStateDone CDMA STATE_IN_SERVICE newNetworkType = " + newNetworkType +
197                " mNewDataConnectionState = " + mNewDataConnectionState);
198        }
199
200        if (DBG) log("pollStateDone: oldSS=[" + ss + "] newSS=[" + newSS + "]");
201
202        boolean hasRegistered = ss.getState() != ServiceState.STATE_IN_SERVICE
203                && newSS.getState() == ServiceState.STATE_IN_SERVICE;
204
205        boolean hasDeregistered = ss.getState() == ServiceState.STATE_IN_SERVICE
206                && newSS.getState() != ServiceState.STATE_IN_SERVICE;
207
208        boolean hasCdmaDataConnectionAttached =
209            mDataConnectionState != ServiceState.STATE_IN_SERVICE
210                && mNewDataConnectionState == ServiceState.STATE_IN_SERVICE;
211
212        boolean hasCdmaDataConnectionDetached =
213            mDataConnectionState == ServiceState.STATE_IN_SERVICE
214                && mNewDataConnectionState != ServiceState.STATE_IN_SERVICE;
215
216        boolean hasCdmaDataConnectionChanged =
217            mDataConnectionState != mNewDataConnectionState;
218
219        boolean hasNetworkTypeChanged = networkType != newNetworkType;
220
221        boolean hasChanged = !newSS.equals(ss);
222
223        boolean hasRoamingOn = !ss.getRoaming() && newSS.getRoaming();
224
225        boolean hasRoamingOff = ss.getRoaming() && !newSS.getRoaming();
226
227        boolean hasLocationChanged = !newCellLoc.equals(cellLoc);
228
229        boolean has4gHandoff =
230                ((networkType == ServiceState.RADIO_TECHNOLOGY_LTE) &&
231                 (newNetworkType == ServiceState.RADIO_TECHNOLOGY_EHRPD)) ||
232                ((networkType == ServiceState.RADIO_TECHNOLOGY_EHRPD) &&
233                 (newNetworkType == ServiceState.RADIO_TECHNOLOGY_LTE));
234
235        boolean hasMultiApnSupport =
236                (((newNetworkType == ServiceState.RADIO_TECHNOLOGY_LTE) ||
237                  (newNetworkType == ServiceState.RADIO_TECHNOLOGY_EHRPD)) &&
238                 ((networkType != ServiceState.RADIO_TECHNOLOGY_LTE) &&
239                  (networkType != ServiceState.RADIO_TECHNOLOGY_EHRPD)));
240
241        boolean hasLostMultiApnSupport =
242            ((newNetworkType >= ServiceState.RADIO_TECHNOLOGY_IS95A) &&
243             (newNetworkType <= ServiceState.RADIO_TECHNOLOGY_EVDO_A));
244
245        if (DBG) {
246            log("pollStateDone:"
247                + " hasRegistered=" + hasRegistered
248                + " hasDeegistered=" + hasDeregistered
249                + " hasCdmaDataConnectionAttached=" + hasCdmaDataConnectionAttached
250                + " hasCdmaDataConnectionDetached=" + hasCdmaDataConnectionDetached
251                + " hasCdmaDataConnectionChanged=" + hasCdmaDataConnectionChanged
252                + " hasNetworkTypeChanged = " + hasNetworkTypeChanged
253                + " hasChanged=" + hasChanged
254                + " hasRoamingOn=" + hasRoamingOn
255                + " hasRoamingOff=" + hasRoamingOff
256                + " hasLocationChanged=" + hasLocationChanged
257                + " has4gHandoff = " + has4gHandoff
258                + " hasMultiApnSupport=" + hasMultiApnSupport
259                + " hasLostMultiApnSupport=" + hasLostMultiApnSupport);
260        }
261        // Add an event log when connection state changes
262        if (ss.getState() != newSS.getState()
263                || mDataConnectionState != mNewDataConnectionState) {
264            EventLog.writeEvent(EventLogTags.CDMA_SERVICE_STATE_CHANGE, ss.getState(),
265                    mDataConnectionState, newSS.getState(), mNewDataConnectionState);
266        }
267
268        ServiceState tss;
269        tss = ss;
270        ss = newSS;
271        newSS = tss;
272        // clean slate for next time
273        newSS.setStateOutOfService();
274        mLteSS.setStateOutOfService();
275
276        if ((hasMultiApnSupport)
277                && (phone.mDataConnectionTracker instanceof CdmaDataConnectionTracker)) {
278            if (DBG) log("GsmDataConnectionTracker Created");
279            phone.mDataConnectionTracker.dispose();
280            phone.mDataConnectionTracker = new GsmDataConnectionTracker(mCdmaLtePhone);
281        }
282
283        if ((hasLostMultiApnSupport)
284                && (phone.mDataConnectionTracker instanceof GsmDataConnectionTracker)) {
285            if (DBG)log("GsmDataConnectionTracker disposed");
286            phone.mDataConnectionTracker.dispose();
287            phone.mDataConnectionTracker = new CdmaDataConnectionTracker(phone);
288        }
289
290        CdmaCellLocation tcl = cellLoc;
291        cellLoc = newCellLoc;
292        newCellLoc = tcl;
293
294        mDataConnectionState = mNewDataConnectionState;
295        networkType = newNetworkType;
296
297        newSS.setStateOutOfService(); // clean slate for next time
298
299        if (hasNetworkTypeChanged) {
300            phone.setSystemProperty(TelephonyProperties.PROPERTY_DATA_NETWORK_TYPE,
301                    ServiceState.radioTechnologyToString(networkType));
302        }
303
304        if (hasRegistered) {
305            mNetworkAttachedRegistrants.notifyRegistrants();
306        }
307
308        if (hasChanged) {
309            if (cm.getNvState().isNVReady()) {
310                String eriText;
311                // Now the CDMAPhone sees the new ServiceState so it can get the
312                // new ERI text
313                if (ss.getState() == ServiceState.STATE_IN_SERVICE) {
314                    eriText = phone.getCdmaEriText();
315                } else {
316                    // Note that ServiceState.STATE_OUT_OF_SERVICE is valid used
317                    // for
318                    // mRegistrationState 0,2,3 and 4
319                    eriText = phone.getContext()
320                            .getText(com.android.internal.R.string.roamingTextSearching).toString();
321                }
322                ss.setOperatorAlphaLong(eriText);
323            }
324            if (cm.getSimState().isSIMReady()) {
325                // SIM is found on the device. Read the operator name from the card.
326                ss.setOperatorAlphaLong(phone.mIccRecords.getServiceProviderName());
327
328                // If SIM card is present, Eri will not be used. Turn it off
329                ss.setCdmaEriIconIndex(EriInfo.ROAMING_INDICATOR_OFF);
330            }
331
332            String operatorNumeric;
333
334            phone.setSystemProperty(TelephonyProperties.PROPERTY_OPERATOR_ALPHA,
335                    ss.getOperatorAlphaLong());
336
337            operatorNumeric = ss.getOperatorNumeric();
338            phone.setSystemProperty(TelephonyProperties.PROPERTY_OPERATOR_NUMERIC, operatorNumeric);
339
340            if (operatorNumeric == null) {
341                phone.setSystemProperty(TelephonyProperties.PROPERTY_OPERATOR_ISO_COUNTRY, "");
342            } else {
343                String isoCountryCode = "";
344                try {
345                    isoCountryCode = MccTable.countryCodeForMcc(Integer.parseInt(operatorNumeric
346                            .substring(0, 3)));
347                } catch (NumberFormatException ex) {
348                    loge("countryCodeForMcc error" + ex);
349                } catch (StringIndexOutOfBoundsException ex) {
350                    loge("countryCodeForMcc error" + ex);
351                }
352
353                phone.setSystemProperty(TelephonyProperties.PROPERTY_OPERATOR_ISO_COUNTRY,
354                        isoCountryCode);
355                mGotCountryCode = true;
356                if (mNeedFixZone) {
357                    fixTimeZone(isoCountryCode);
358                }
359            }
360
361            phone.setSystemProperty(TelephonyProperties.PROPERTY_OPERATOR_ISROAMING,
362                    ss.getRoaming() ? "true" : "false");
363
364            updateSpnDisplay();
365            phone.notifyServiceStateChanged(ss);
366        }
367
368        if (hasCdmaDataConnectionAttached) {
369            mAttachedRegistrants.notifyRegistrants();
370        }
371
372        if (hasCdmaDataConnectionDetached) {
373            mDetachedRegistrants.notifyRegistrants();
374        }
375
376        if ((hasCdmaDataConnectionChanged || hasNetworkTypeChanged)) {
377            phone.notifyDataConnection();
378        }
379
380        if (hasRoamingOn) {
381            mRoamingOnRegistrants.notifyRegistrants();
382        }
383
384        if (hasRoamingOff) {
385            mRoamingOffRegistrants.notifyRegistrants();
386        }
387
388        if (hasLocationChanged) {
389            phone.notifyLocationChanged();
390        }
391    }
392
393    @Override
394    protected void onSignalStrengthResult(AsyncResult ar) {
395        SignalStrength oldSignalStrength = mSignalStrength;
396
397        if (ar.exception != null) {
398            // Most likely radio is resetting/disconnected change to default
399            // values.
400            setSignalStrengthDefaultValues();
401        } else {
402            int[] ints = (int[])ar.result;
403            int lteCqi = 99, lteRsrp = -1;
404            int lteRssi = 99;
405            int offset = 2;
406            int cdmaDbm = (ints[offset] > 0) ? -ints[offset] : -120;
407            int cdmaEcio = (ints[offset + 1] > 0) ? -ints[offset + 1] : -160;
408            int evdoRssi = (ints[offset + 2] > 0) ? -ints[offset + 2] : -120;
409            int evdoEcio = (ints[offset + 3] > 0) ? -ints[offset + 3] : -1;
410            int evdoSnr = ((ints[offset + 4] > 0) && (ints[offset + 4] <= 8)) ? ints[offset + 4]
411                    : -1;
412            if (networkType == ServiceState.RADIO_TECHNOLOGY_LTE) {
413                lteRssi = (ints[offset + 5] >= 0) ? ints[offset + 5] : 99;
414                lteRsrp = (ints[offset + 6] < 0) ? ints[offset + 6] : -1;
415                lteCqi = (ints[offset + 7] >= 0) ? ints[offset + 7] : 99;
416            }
417
418            if (networkType != ServiceState.RADIO_TECHNOLOGY_LTE) {
419                mSignalStrength = new SignalStrength(99, -1, cdmaDbm, cdmaEcio, evdoRssi, evdoEcio,
420                        evdoSnr, false);
421            } else {
422                mSignalStrength = new SignalStrength(99, -1, cdmaDbm, cdmaEcio, evdoRssi, evdoEcio,
423                        evdoSnr, lteRssi, lteRsrp, -1, -1, lteCqi, true);
424            }
425        }
426
427        try {
428            phone.notifySignalStrength();
429        } catch (NullPointerException ex) {
430            loge("onSignalStrengthResult() Phone already destroyed: " + ex
431                    + "SignalStrength not notified");
432        }
433    }
434
435    @Override
436    public boolean isConcurrentVoiceAndDataAllowed() {
437        // Note: it needs to be confirmed which CDMA network types
438        // can support voice and data calls concurrently.
439        // For the time-being, the return value will be false.
440        // return (networkType >= ServiceState.RADIO_TECHNOLOGY_LTE);
441        return false;
442    }
443
444    /**
445     * Returns OTASP_NOT_NEEDED as its not needed for LTE
446     */
447    @Override
448    int getOtasp() {
449        int provisioningState = OTASP_NOT_NEEDED;
450        if (DBG) log("getOtasp: state=" + provisioningState);
451        return provisioningState;
452    }
453
454    @Override
455    protected void log(String s) {
456        Log.d(LOG_TAG, "[CdmaLteSST] " + s);
457    }
458
459    @Override
460    protected void loge(String s) {
461        Log.e(LOG_TAG, "[CdmaLteSST] " + s);
462    }
463}
464