CdmaLteServiceStateTracker.java revision f1b97fcff40f829cafd2fa643e8e4b788e504614
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 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.uicc.RuimRecords;
23import com.android.internal.telephony.uicc.IccCardApplicationStatus.AppState;
24
25import android.telephony.CellInfo;
26import android.telephony.CellInfoLte;
27import android.telephony.CellSignalStrengthLte;
28import android.telephony.CellIdentityLte;
29import android.telephony.SignalStrength;
30import android.telephony.ServiceState;
31import android.telephony.cdma.CdmaCellLocation;
32import android.text.TextUtils;
33import android.os.AsyncResult;
34import android.os.Message;
35import android.os.SystemClock;
36import android.os.SystemProperties;
37
38import android.telephony.Rlog;
39import android.util.EventLog;
40
41import java.io.FileDescriptor;
42import java.io.PrintWriter;
43import java.util.ArrayList;
44import java.util.List;
45
46public class CdmaLteServiceStateTracker extends CdmaServiceStateTracker {
47    private CDMALTEPhone mCdmaLtePhone;
48    private final CellInfoLte mCellInfoLte;
49
50    private CellIdentityLte mNewCellIdentityLte = new CellIdentityLte();
51    private CellIdentityLte mLasteCellIdentityLte = new CellIdentityLte();
52
53    public CdmaLteServiceStateTracker(CDMALTEPhone phone) {
54        super(phone, new CellInfoLte());
55        mCdmaLtePhone = phone;
56        mCellInfoLte = (CellInfoLte) mCellInfo;
57
58        ((CellInfoLte)mCellInfo).setCellSignalStrength(new CellSignalStrengthLte());
59        ((CellInfoLte)mCellInfo).setCellIdentity(new CellIdentityLte());
60
61        if (DBG) log("CdmaLteServiceStateTracker Constructors");
62    }
63
64    @Override
65    public void handleMessage(Message msg) {
66        AsyncResult ar;
67        int[] ints;
68        String[] strings;
69        switch (msg.what) {
70        case EVENT_POLL_STATE_GPRS:
71            if (DBG) log("handleMessage EVENT_POLL_STATE_GPRS");
72            ar = (AsyncResult)msg.obj;
73            handlePollStateResult(msg.what, ar);
74            break;
75        case EVENT_RUIM_RECORDS_LOADED:
76            RuimRecords ruim = (RuimRecords)mIccRecords;
77            if ((ruim != null) && ruim.isProvisioned()) {
78                mMdn = ruim.getMdn();
79                mMin = ruim.getMin();
80                parseSidNid(ruim.getSid(), ruim.getNid());
81                mPrlVersion = ruim.getPrlVersion();
82                mIsMinInfoReady = true;
83                updateOtaspState();
84            }
85            // SID/NID/PRL is loaded. Poll service state
86            // again to update to the roaming state with
87            // the latest variables.
88            pollState();
89            break;
90        default:
91            super.handleMessage(msg);
92        }
93    }
94
95    /**
96     * Handle the result of one of the pollState()-related requests
97     */
98    @Override
99    protected void handlePollStateResultMessage(int what, AsyncResult ar) {
100        if (what == EVENT_POLL_STATE_GPRS) {
101            String states[] = (String[])ar.result;
102            if (DBG) {
103                log("handlePollStateResultMessage: EVENT_POLL_STATE_GPRS states.length=" +
104                        states.length + " states=" + states);
105            }
106
107            int type = 0;
108            int regState = -1;
109            if (states.length > 0) {
110                try {
111                    regState = Integer.parseInt(states[0]);
112
113                    // states[3] (if present) is the current radio technology
114                    if (states.length >= 4 && states[3] != null) {
115                        type = Integer.parseInt(states[3]);
116                    }
117                } catch (NumberFormatException ex) {
118                    loge("handlePollStateResultMessage: error parsing GprsRegistrationState: "
119                                    + ex);
120                }
121                if (states.length >= 10) {
122                    int mcc;
123                    int mnc;
124                    int tac;
125                    int pci;
126                    int eci;
127                    int csgid;
128                    String operatorNumeric = null;
129
130                    try {
131                        operatorNumeric = mNewSS.getOperatorNumeric();
132                        mcc = Integer.parseInt(operatorNumeric.substring(0,3));
133                    } catch (Exception e) {
134                        try {
135                            operatorNumeric = mSS.getOperatorNumeric();
136                            mcc = Integer.parseInt(operatorNumeric.substring(0,3));
137                        } catch (Exception ex) {
138                            loge("handlePollStateResultMessage: bad mcc operatorNumeric=" +
139                                    operatorNumeric + " ex=" + ex);
140                            operatorNumeric = "";
141                            mcc = Integer.MAX_VALUE;
142                        }
143                    }
144                    try {
145                        mnc = Integer.parseInt(operatorNumeric.substring(3));
146                    } catch (Exception e) {
147                        loge("handlePollStateResultMessage: bad mnc operatorNumeric=" +
148                                operatorNumeric + " e=" + e);
149                        mnc = Integer.MAX_VALUE;
150                    }
151
152                    // Use Integer#decode to be generous in what we receive and allow
153                    // decimal, hex or octal values.
154                    try {
155                        tac = Integer.decode(states[6]);
156                    } catch (Exception e) {
157                        loge("handlePollStateResultMessage: bad tac states[6]=" +
158                                states[6] + " e=" + e);
159                        tac = Integer.MAX_VALUE;
160                    }
161                    try {
162                        pci = Integer.decode(states[7]);
163                    } catch (Exception e) {
164                        loge("handlePollStateResultMessage: bad pci states[7]=" +
165                                states[7] + " e=" + e);
166                        pci = Integer.MAX_VALUE;
167                    }
168                    try {
169                        eci = Integer.decode(states[8]);
170                    } catch (Exception e) {
171                        loge("handlePollStateResultMessage: bad eci states[8]=" +
172                                states[8] + " e=" + e);
173                        eci = Integer.MAX_VALUE;
174                    }
175                    try {
176                        csgid = Integer.decode(states[9]);
177                    } catch (Exception e) {
178                        // FIX: Always bad so don't pollute the logs
179                        // loge("handlePollStateResultMessage: bad csgid states[9]=" +
180                        //        states[9] + " e=" + e);
181                        csgid = Integer.MAX_VALUE;
182                    }
183                    mNewCellIdentityLte = new CellIdentityLte(mcc, mnc, eci, pci, tac);
184                    if (DBG) {
185                        log("handlePollStateResultMessage: mNewLteCellIdentity=" +
186                                mNewCellIdentityLte);
187                    }
188                }
189            }
190
191            mNewSS.setRilDataRadioTechnology(type);
192            int dataRegState = regCodeToServiceState(regState);
193            mNewSS.setDataRegState(dataRegState);
194            if (DBG) {
195                log("handlPollStateResultMessage: CdmaLteSST setDataRegState=" + dataRegState
196                        + " regState=" + regState
197                        + " dataRadioTechnology=" + type);
198            }
199        } else {
200            super.handlePollStateResultMessage(what, ar);
201        }
202    }
203
204    @Override
205    protected void pollState() {
206        mPollingContext = new int[1];
207        mPollingContext[0] = 0;
208
209        switch (mCi.getRadioState()) {
210            case RADIO_UNAVAILABLE:
211                mNewSS.setStateOutOfService();
212                mNewCellLoc.setStateInvalid();
213                setSignalStrengthDefaultValues();
214                mGotCountryCode = false;
215
216                pollStateDone();
217                break;
218
219            case RADIO_OFF:
220                mNewSS.setStateOff();
221                mNewCellLoc.setStateInvalid();
222                setSignalStrengthDefaultValues();
223                mGotCountryCode = false;
224
225                pollStateDone();
226                break;
227
228            default:
229                // Issue all poll-related commands at once, then count
230                // down the responses which are allowed to arrive
231                // out-of-order.
232
233                mPollingContext[0]++;
234                // RIL_REQUEST_OPERATOR is necessary for CDMA
235                mCi.getOperator(obtainMessage(EVENT_POLL_STATE_OPERATOR_CDMA, mPollingContext));
236
237                mPollingContext[0]++;
238                // RIL_REQUEST_VOICE_REGISTRATION_STATE is necessary for CDMA
239                mCi.getVoiceRegistrationState(obtainMessage(EVENT_POLL_STATE_REGISTRATION_CDMA,
240                        mPollingContext));
241
242                mPollingContext[0]++;
243                // RIL_REQUEST_DATA_REGISTRATION_STATE
244                mCi.getDataRegistrationState(obtainMessage(EVENT_POLL_STATE_GPRS,
245                                            mPollingContext));
246                break;
247        }
248    }
249
250    @Override
251    protected void pollStateDone() {
252        log("pollStateDone: lte 1 ss=[" + mSS + "] newSS=[" + mNewSS + "]");
253
254        boolean hasRegistered = mSS.getVoiceRegState() != ServiceState.STATE_IN_SERVICE
255                && mNewSS.getVoiceRegState() == ServiceState.STATE_IN_SERVICE;
256
257        boolean hasDeregistered = mSS.getVoiceRegState() == ServiceState.STATE_IN_SERVICE
258                && mNewSS.getVoiceRegState() != ServiceState.STATE_IN_SERVICE;
259
260        boolean hasCdmaDataConnectionAttached =
261            mSS.getDataRegState() != ServiceState.STATE_IN_SERVICE
262                && mNewSS.getDataRegState() == ServiceState.STATE_IN_SERVICE;
263
264        boolean hasCdmaDataConnectionDetached =
265                mSS.getDataRegState() == ServiceState.STATE_IN_SERVICE
266                && mNewSS.getDataRegState() != ServiceState.STATE_IN_SERVICE;
267
268        boolean hasCdmaDataConnectionChanged =
269            mSS.getDataRegState() != mNewSS.getDataRegState();
270
271        boolean hasVoiceRadioTechnologyChanged = mSS.getRilVoiceRadioTechnology()
272                != mNewSS.getRilVoiceRadioTechnology();
273
274        boolean hasDataRadioTechnologyChanged = mSS.getRilDataRadioTechnology()
275                != mNewSS.getRilDataRadioTechnology();
276
277        boolean hasChanged = !mNewSS.equals(mSS);
278
279        boolean hasRoamingOn = !mSS.getRoaming() && mNewSS.getRoaming();
280
281        boolean hasRoamingOff = mSS.getRoaming() && !mNewSS.getRoaming();
282
283        boolean hasLocationChanged = !mNewCellLoc.equals(mCellLoc);
284
285        boolean has4gHandoff =
286                mNewSS.getDataRegState() == ServiceState.STATE_IN_SERVICE &&
287                (((mSS.getRilDataRadioTechnology() == ServiceState.RIL_RADIO_TECHNOLOGY_LTE) &&
288                  (mNewSS.getRilDataRadioTechnology() == ServiceState.RIL_RADIO_TECHNOLOGY_EHRPD)) ||
289                 ((mSS.getRilDataRadioTechnology() == ServiceState.RIL_RADIO_TECHNOLOGY_EHRPD) &&
290                  (mNewSS.getRilDataRadioTechnology() == ServiceState.RIL_RADIO_TECHNOLOGY_LTE)));
291
292        boolean hasMultiApnSupport =
293                (((mNewSS.getRilDataRadioTechnology() == ServiceState.RIL_RADIO_TECHNOLOGY_LTE) ||
294                  (mNewSS.getRilDataRadioTechnology() == ServiceState.RIL_RADIO_TECHNOLOGY_EHRPD)) &&
295                 ((mSS.getRilDataRadioTechnology() != ServiceState.RIL_RADIO_TECHNOLOGY_LTE) &&
296                  (mSS.getRilDataRadioTechnology() != ServiceState.RIL_RADIO_TECHNOLOGY_EHRPD)));
297
298        boolean hasLostMultiApnSupport =
299            ((mNewSS.getRilDataRadioTechnology() >= ServiceState.RIL_RADIO_TECHNOLOGY_IS95A) &&
300             (mNewSS.getRilDataRadioTechnology() <= ServiceState.RIL_RADIO_TECHNOLOGY_EVDO_A));
301
302        if (DBG) {
303            log("pollStateDone:"
304                + " hasRegistered=" + hasRegistered
305                + " hasDeegistered=" + hasDeregistered
306                + " hasCdmaDataConnectionAttached=" + hasCdmaDataConnectionAttached
307                + " hasCdmaDataConnectionDetached=" + hasCdmaDataConnectionDetached
308                + " hasCdmaDataConnectionChanged=" + hasCdmaDataConnectionChanged
309                + " hasVoiceRadioTechnologyChanged= " + hasVoiceRadioTechnologyChanged
310                + " hasDataRadioTechnologyChanged=" + hasDataRadioTechnologyChanged
311                + " hasChanged=" + hasChanged
312                + " hasRoamingOn=" + hasRoamingOn
313                + " hasRoamingOff=" + hasRoamingOff
314                + " hasLocationChanged=" + hasLocationChanged
315                + " has4gHandoff = " + has4gHandoff
316                + " hasMultiApnSupport=" + hasMultiApnSupport
317                + " hasLostMultiApnSupport=" + hasLostMultiApnSupport);
318        }
319        // Add an event log when connection state changes
320        if (mSS.getVoiceRegState() != mNewSS.getVoiceRegState()
321                || mSS.getDataRegState() != mNewSS.getDataRegState()) {
322            EventLog.writeEvent(EventLogTags.CDMA_SERVICE_STATE_CHANGE, mSS.getVoiceRegState(),
323                    mSS.getDataRegState(), mNewSS.getVoiceRegState(), mNewSS.getDataRegState());
324        }
325
326        ServiceState tss;
327        tss = mSS;
328        mSS = mNewSS;
329        mNewSS = tss;
330        // clean slate for next time
331        mNewSS.setStateOutOfService();
332
333        CdmaCellLocation tcl = mCellLoc;
334        mCellLoc = mNewCellLoc;
335        mNewCellLoc = tcl;
336
337        mNewSS.setStateOutOfService(); // clean slate for next time
338
339        if (hasVoiceRadioTechnologyChanged) {
340            mPhone.setSystemProperty(TelephonyProperties.PROPERTY_DATA_NETWORK_TYPE,
341                    ServiceState.rilRadioTechnologyToString(mSS.getRilDataRadioTechnology()));
342        }
343
344        if (hasRegistered) {
345            mNetworkAttachedRegistrants.notifyRegistrants();
346        }
347
348        if (hasChanged) {
349            if (mPhone.isEriFileLoaded()) {
350                String eriText;
351                // Now the CDMAPhone sees the new ServiceState so it can get the
352                // new ERI text
353                if (mSS.getVoiceRegState() == ServiceState.STATE_IN_SERVICE) {
354                    eriText = mPhone.getCdmaEriText();
355                } else if (mSS.getVoiceRegState() == ServiceState.STATE_POWER_OFF) {
356                    eriText = (mIccRecords != null) ? mIccRecords.getServiceProviderName() : null;
357                    if (TextUtils.isEmpty(eriText)) {
358                        // Sets operator alpha property by retrieving from
359                        // build-time system property
360                        eriText = SystemProperties.get("ro.cdma.home.operator.alpha");
361                    }
362                } else {
363                    // Note that ServiceState.STATE_OUT_OF_SERVICE is valid used
364                    // for mRegistrationState 0,2,3 and 4
365                    eriText = mPhone.getContext()
366                            .getText(com.android.internal.R.string.roamingTextSearching).toString();
367                }
368                mSS.setOperatorAlphaLong(eriText);
369            }
370
371            if (mUiccApplcation != null && mUiccApplcation.getState() == AppState.APPSTATE_READY &&
372                    mIccRecords != null) {
373                // SIM is found on the device. If ERI roaming is OFF, and SID/NID matches
374                // one configured in SIM, use operator name  from CSIM record.
375                boolean showSpn =
376                    ((RuimRecords)mIccRecords).getCsimSpnDisplayCondition();
377                int iconIndex = mSS.getCdmaEriIconIndex();
378
379                if (showSpn && (iconIndex == EriInfo.ROAMING_INDICATOR_OFF) &&
380                    isInHomeSidNid(mSS.getSystemId(), mSS.getNetworkId()) &&
381                    mIccRecords != null) {
382                    mSS.setOperatorAlphaLong(mIccRecords.getServiceProviderName());
383                }
384            }
385
386            String operatorNumeric;
387
388            mPhone.setSystemProperty(TelephonyProperties.PROPERTY_OPERATOR_ALPHA,
389                    mSS.getOperatorAlphaLong());
390
391            String prevOperatorNumeric =
392                    SystemProperties.get(TelephonyProperties.PROPERTY_OPERATOR_NUMERIC, "");
393            operatorNumeric = mSS.getOperatorNumeric();
394            mPhone.setSystemProperty(TelephonyProperties.PROPERTY_OPERATOR_NUMERIC, operatorNumeric);
395
396            if (operatorNumeric == null) {
397                if (DBG) log("operatorNumeric is null");
398                mPhone.setSystemProperty(TelephonyProperties.PROPERTY_OPERATOR_ISO_COUNTRY, "");
399                mGotCountryCode = false;
400            } else {
401                String isoCountryCode = "";
402                String mcc = operatorNumeric.substring(0, 3);
403                try {
404                    isoCountryCode = MccTable.countryCodeForMcc(Integer.parseInt(operatorNumeric
405                            .substring(0, 3)));
406                } catch (NumberFormatException ex) {
407                    loge("countryCodeForMcc error" + ex);
408                } catch (StringIndexOutOfBoundsException ex) {
409                    loge("countryCodeForMcc error" + ex);
410                }
411
412                mPhone.setSystemProperty(TelephonyProperties.PROPERTY_OPERATOR_ISO_COUNTRY,
413                        isoCountryCode);
414                mGotCountryCode = true;
415
416                if (shouldFixTimeZoneNow(mPhone, operatorNumeric, prevOperatorNumeric,
417                        mNeedFixZone)) {
418                    fixTimeZone(isoCountryCode);
419                }
420            }
421
422            mPhone.setSystemProperty(TelephonyProperties.PROPERTY_OPERATOR_ISROAMING,
423                    mSS.getRoaming() ? "true" : "false");
424
425            updateSpnDisplay();
426            mPhone.notifyServiceStateChanged(mSS);
427        }
428
429        if (hasCdmaDataConnectionAttached || has4gHandoff) {
430            mAttachedRegistrants.notifyRegistrants();
431        }
432
433        if (hasCdmaDataConnectionDetached) {
434            mDetachedRegistrants.notifyRegistrants();
435        }
436
437        if ((hasCdmaDataConnectionChanged || hasDataRadioTechnologyChanged)) {
438            log("pollStateDone: call notifyDataConnection");
439            mPhone.notifyDataConnection(null);
440        }
441
442        if (hasRoamingOn) {
443            mRoamingOnRegistrants.notifyRegistrants();
444        }
445
446        if (hasRoamingOff) {
447            mRoamingOffRegistrants.notifyRegistrants();
448        }
449
450        if (hasLocationChanged) {
451            mPhone.notifyLocationChanged();
452        }
453
454        ArrayList<CellInfo> arrayCi = new ArrayList<CellInfo>();
455        synchronized(mCellInfo) {
456            CellInfoLte cil = (CellInfoLte)mCellInfo;
457
458            boolean cidChanged = ! mNewCellIdentityLte.equals(mLasteCellIdentityLte);
459            if (hasRegistered || hasDeregistered || cidChanged) {
460                // TODO: Handle the absence of LteCellIdentity
461                long timeStamp = SystemClock.elapsedRealtime() * 1000;
462                boolean registered = mSS.getVoiceRegState() == ServiceState.STATE_IN_SERVICE;
463                mLasteCellIdentityLte = mNewCellIdentityLte;
464
465                cil.setRegisterd(registered);
466                cil.setCellIdentity(mLasteCellIdentityLte);
467                if (DBG) {
468                    log("pollStateDone: hasRegistered=" + hasRegistered +
469                            " hasDeregistered=" + hasDeregistered +
470                            " cidChanged=" + cidChanged +
471                            " mCellInfo=" + mCellInfo);
472                }
473                arrayCi.add(mCellInfo);
474            }
475            mPhoneBase.notifyCellInfo(arrayCi);
476        }
477    }
478
479    @Override
480    protected boolean onSignalStrengthResult(AsyncResult ar, boolean isGsm) {
481        if (mSS.getRilDataRadioTechnology() == ServiceState.RIL_RADIO_TECHNOLOGY_LTE) {
482            isGsm = true;
483        }
484        boolean ssChanged = super.onSignalStrengthResult(ar, isGsm);
485
486        synchronized (mCellInfo) {
487            if (mSS.getRilDataRadioTechnology() == ServiceState.RIL_RADIO_TECHNOLOGY_LTE) {
488                mCellInfoLte.setTimeStamp(SystemClock.elapsedRealtime() * 1000);
489                mCellInfoLte.setTimeStampType(CellInfo.TIMESTAMP_TYPE_JAVA_RIL);
490                mCellInfoLte.getCellSignalStrength()
491                                .initialize(mSignalStrength,SignalStrength.INVALID);
492            }
493            if (mCellInfoLte.getCellIdentity() != null) {
494                ArrayList<CellInfo> arrayCi = new ArrayList<CellInfo>();
495                arrayCi.add(mCellInfoLte);
496                mPhoneBase.notifyCellInfo(arrayCi);
497            }
498        }
499        return ssChanged;
500    }
501
502    @Override
503    public boolean isConcurrentVoiceAndDataAllowed() {
504        // For non-LTE, look at the CSS indicator to check on Concurrent V & D capability
505        if (mSS.getRilDataRadioTechnology() == ServiceState.RIL_RADIO_TECHNOLOGY_LTE) {
506            return true;
507        } else {
508            return mSS.getCssIndicator() == 1;
509        }
510    }
511
512    /**
513     * Check whether the specified SID and NID pair appears in the HOME SID/NID list
514     * read from NV or SIM.
515     *
516     * @return true if provided sid/nid pair belongs to operator's home network.
517     */
518    private boolean isInHomeSidNid(int sid, int nid) {
519        // if SID/NID is not available, assume this is home network.
520        if (isSidsAllZeros()) return true;
521
522        // length of SID/NID shold be same
523        if (mHomeSystemId.length != mHomeNetworkId.length) return true;
524
525        if (sid == 0) return true;
526
527        for (int i = 0; i < mHomeSystemId.length; i++) {
528            // Use SID only if NID is a reserved value.
529            // SID 0 and NID 0 and 65535 are reserved. (C.0005 2.6.5.2)
530            if ((mHomeSystemId[i] == sid) &&
531                ((mHomeNetworkId[i] == 0) || (mHomeNetworkId[i] == 65535) ||
532                 (nid == 0) || (nid == 65535) || (mHomeNetworkId[i] == nid))) {
533                return true;
534            }
535        }
536        // SID/NID are not in the list. So device is not in home network
537        return false;
538    }
539
540    /**
541     * @return all available cell information, the returned List maybe empty but never null.
542     */
543    @Override
544    public List<CellInfo> getAllCellInfo() {
545        ArrayList<CellInfo> arrayList = new ArrayList<CellInfo>();
546        CellInfo ci;
547        synchronized(mCellInfo) {
548            arrayList.add(mCellInfoLte);
549        }
550        if (DBG) log ("getAllCellInfo: arrayList=" + arrayList);
551        return arrayList;
552    }
553
554    @Override
555    protected void log(String s) {
556        Rlog.d(LOG_TAG, "[CdmaLteSST] " + s);
557    }
558
559    @Override
560    protected void loge(String s) {
561        Rlog.e(LOG_TAG, "[CdmaLteSST] " + s);
562    }
563
564    @Override
565    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
566        pw.println("CdmaLteServiceStateTracker extends:");
567        super.dump(fd, pw, args);
568        pw.println(" mCdmaLtePhone=" + mCdmaLtePhone);
569    }
570}
571