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