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