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