c19cc5efd1db2e5142e71fd56e13f4c049ad67b9
[android/platform/frameworks/opt/telephony.git] / src / java / com / android / internal / telephony / cdma / CdmaLteServiceStateTracker.java
1 /*
2  * Copyright (C) 2008 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 package com.android.internal.telephony.cdma;
18
19 import com.android.internal.telephony.PhoneBase;
20 import com.android.internal.telephony.TelephonyProperties;
21 import com.android.internal.telephony.MccTable;
22 import com.android.internal.telephony.EventLogTags;
23 import com.android.internal.telephony.RILConstants;
24 import com.android.internal.telephony.IccCard;
25
26 import android.content.Intent;
27 import android.telephony.SignalStrength;
28 import android.telephony.ServiceState;
29 import android.telephony.cdma.CdmaCellLocation;
30 import android.os.AsyncResult;
31 import android.os.Message;
32 import android.os.SystemProperties;
33
34 import android.text.TextUtils;
35 import android.util.Log;
36 import android.util.EventLog;
37
38 import com.android.internal.telephony.gsm.GsmDataConnectionTracker;
39 import com.android.internal.telephony.IccCardConstants;
40
41 import java.io.FileDescriptor;
42 import java.io.PrintWriter;
43
44 public class CdmaLteServiceStateTracker extends CdmaServiceStateTracker {
45     CDMALTEPhone mCdmaLtePhone;
46
47     private ServiceState  mLteSS;  // The last LTE state from Voice Registration
48
49     public CdmaLteServiceStateTracker(CDMALTEPhone phone) {
50         super(phone);
51         mCdmaLtePhone = phone;
52
53         mLteSS = new ServiceState();
54         if (DBG) log("CdmaLteServiceStateTracker Constructors");
55     }
56
57     @Override
58     public void handleMessage(Message msg) {
59         AsyncResult ar;
60         int[] ints;
61         String[] strings;
62         switch (msg.what) {
63         case EVENT_POLL_STATE_GPRS:
64             if (DBG) log("handleMessage EVENT_POLL_STATE_GPRS");
65             ar = (AsyncResult)msg.obj;
66             handlePollStateResult(msg.what, ar);
67             break;
68         case EVENT_RUIM_RECORDS_LOADED:
69             CdmaLteUiccRecords sim = (CdmaLteUiccRecords)mIccRecords;
70             if ((sim != null) && sim.isProvisioned()) {
71                 mMdn = sim.getMdn();
72                 mMin = sim.getMin();
73                 parseSidNid(sim.getSid(), sim.getNid());
74                 mPrlVersion = sim.getPrlVersion();;
75                 mIsMinInfoReady = true;
76                 updateOtaspState();
77             }
78             // SID/NID/PRL is loaded. Poll service state
79             // again to update to the roaming state with
80             // the latest variables.
81             pollState();
82             break;
83         default:
84             super.handleMessage(msg);
85         }
86     }
87
88     /**
89      * Set the cdmaSS for EVENT_POLL_STATE_REGISTRATION_CDMA
90      */
91     @Override
92     protected void setCdmaTechnology(int radioTechnology) {
93         // Called on voice registration state response.
94         // Just record new CDMA radio technology
95         newSS.setRadioTechnology(radioTechnology);
96     }
97
98     /**
99      * Handle the result of one of the pollState()-related requests
100      */
101     @Override
102     protected void handlePollStateResultMessage(int what, AsyncResult ar) {
103         if (what == EVENT_POLL_STATE_GPRS) {
104             if (DBG) log("handlePollStateResultMessage: EVENT_POLL_STATE_GPRS");
105             String states[] = (String[])ar.result;
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             }
122
123             mLteSS.setRadioTechnology(type);
124             mLteSS.setState(regCodeToServiceState(regState));
125         } else {
126             super.handlePollStateResultMessage(what, ar);
127         }
128     }
129
130     @Override
131     protected void pollState() {
132         pollingContext = new int[1];
133         pollingContext[0] = 0;
134
135         switch (cm.getRadioState()) {
136             case RADIO_UNAVAILABLE:
137                 newSS.setStateOutOfService();
138                 newCellLoc.setStateInvalid();
139                 setSignalStrengthDefaultValues();
140                 mGotCountryCode = false;
141
142                 pollStateDone();
143                 break;
144
145             case RADIO_OFF:
146                 newSS.setStateOff();
147                 newCellLoc.setStateInvalid();
148                 setSignalStrengthDefaultValues();
149                 mGotCountryCode = false;
150
151                 pollStateDone();
152                 break;
153
154             default:
155                 // Issue all poll-related commands at once, then count
156                 // down the responses which are allowed to arrive
157                 // out-of-order.
158
159                 pollingContext[0]++;
160                 // RIL_REQUEST_OPERATOR is necessary for CDMA
161                 cm.getOperator(obtainMessage(EVENT_POLL_STATE_OPERATOR_CDMA, pollingContext));
162
163                 pollingContext[0]++;
164                 // RIL_REQUEST_VOICE_REGISTRATION_STATE is necessary for CDMA
165                 cm.getVoiceRegistrationState(obtainMessage(EVENT_POLL_STATE_REGISTRATION_CDMA,
166                         pollingContext));
167
168                 int networkMode = android.provider.Settings.Secure.getInt(phone.getContext()
169                         .getContentResolver(),
170                         android.provider.Settings.Secure.PREFERRED_NETWORK_MODE,
171                         RILConstants.PREFERRED_NETWORK_MODE);
172                 if (DBG) log("pollState: network mode here is = " + networkMode);
173                 if ((networkMode == RILConstants.NETWORK_MODE_GLOBAL)
174                         || (networkMode == RILConstants.NETWORK_MODE_LTE_ONLY)) {
175                     pollingContext[0]++;
176                     // RIL_REQUEST_DATA_REGISTRATION_STATE
177                     cm.getDataRegistrationState(obtainMessage(EVENT_POLL_STATE_GPRS,
178                                                 pollingContext));
179                 }
180                 break;
181         }
182     }
183
184     @Override
185     protected void pollStateDone() {
186         // determine data RadioTechnology from both LET and CDMA SS
187         if (mLteSS.getState() == ServiceState.STATE_IN_SERVICE) {
188             //in LTE service
189             mNewRilRadioTechnology = mLteSS.getRilRadioTechnology();
190             mNewDataConnectionState = mLteSS.getState();
191             newSS.setRadioTechnology(mNewRilRadioTechnology);
192             log("pollStateDone LTE/eHRPD STATE_IN_SERVICE mNewRilRadioTechnology = " +
193                     mNewRilRadioTechnology);
194         } else {
195             // LTE out of service, get CDMA Service State
196             mNewRilRadioTechnology = newSS.getRilRadioTechnology();
197             mNewDataConnectionState = radioTechnologyToDataServiceState(mNewRilRadioTechnology);
198             log("pollStateDone CDMA STATE_IN_SERVICE mNewRilRadioTechnology = " +
199                     mNewRilRadioTechnology + " mNewDataConnectionState = " +
200                     mNewDataConnectionState);
201         }
202
203         // TODO: Add proper support for LTE Only, we should be looking at
204         //       the preferred network mode, to know when newSS state should
205         //       be coming from mLteSs state. This was needed to pass a VZW
206         //       LTE Only test.
207         //
208         // If CDMA service is OOS, double check if the device is running with LTE only
209         // mode. If that is the case, derive the service state from LTE side.
210         // To set in LTE only mode, sqlite3 /data/data/com.android.providers.settings/
211         // databases/settings.db "update secure set value='11' where name='preferred_network_mode'"
212         if (newSS.getState() == ServiceState.STATE_OUT_OF_SERVICE) {
213             int networkMode = android.provider.Settings.Secure.getInt(phone.getContext()
214                                   .getContentResolver(),
215                                   android.provider.Settings.Secure.PREFERRED_NETWORK_MODE,
216                                   RILConstants.PREFERRED_NETWORK_MODE);
217             if (networkMode == RILConstants.NETWORK_MODE_LTE_ONLY) {
218                 if (DBG) log("pollState: LTE Only mode");
219                 newSS.setState(mLteSS.getState());
220             }
221         }
222
223         if (DBG) log("pollStateDone: oldSS=[" + ss + "] newSS=[" + newSS + "]");
224
225         boolean hasRegistered = ss.getState() != ServiceState.STATE_IN_SERVICE
226                 && newSS.getState() == ServiceState.STATE_IN_SERVICE;
227
228         boolean hasDeregistered = ss.getState() == ServiceState.STATE_IN_SERVICE
229                 && newSS.getState() != ServiceState.STATE_IN_SERVICE;
230
231         boolean hasCdmaDataConnectionAttached =
232             mDataConnectionState != ServiceState.STATE_IN_SERVICE
233                 && mNewDataConnectionState == ServiceState.STATE_IN_SERVICE;
234
235         boolean hasCdmaDataConnectionDetached =
236             mDataConnectionState == ServiceState.STATE_IN_SERVICE
237                 && mNewDataConnectionState != ServiceState.STATE_IN_SERVICE;
238
239         boolean hasCdmaDataConnectionChanged =
240             mDataConnectionState != mNewDataConnectionState;
241
242         boolean hasRadioTechnologyChanged = mRilRadioTechnology != mNewRilRadioTechnology;
243
244         boolean hasChanged = !newSS.equals(ss);
245
246         boolean hasRoamingOn = !ss.getRoaming() && newSS.getRoaming();
247
248         boolean hasRoamingOff = ss.getRoaming() && !newSS.getRoaming();
249
250         boolean hasLocationChanged = !newCellLoc.equals(cellLoc);
251
252         boolean has4gHandoff =
253                 mNewDataConnectionState == ServiceState.STATE_IN_SERVICE &&
254                 (((mRilRadioTechnology == ServiceState.RIL_RADIO_TECHNOLOGY_LTE) &&
255                   (mNewRilRadioTechnology == ServiceState.RIL_RADIO_TECHNOLOGY_EHRPD)) ||
256                  ((mRilRadioTechnology == ServiceState.RIL_RADIO_TECHNOLOGY_EHRPD) &&
257                   (mNewRilRadioTechnology == ServiceState.RIL_RADIO_TECHNOLOGY_LTE)));
258
259         boolean hasMultiApnSupport =
260                 (((mNewRilRadioTechnology == ServiceState.RIL_RADIO_TECHNOLOGY_LTE) ||
261                   (mNewRilRadioTechnology == ServiceState.RIL_RADIO_TECHNOLOGY_EHRPD)) &&
262                  ((mRilRadioTechnology != ServiceState.RIL_RADIO_TECHNOLOGY_LTE) &&
263                   (mRilRadioTechnology != ServiceState.RIL_RADIO_TECHNOLOGY_EHRPD)));
264
265         boolean hasLostMultiApnSupport =
266             ((mNewRilRadioTechnology >= ServiceState.RIL_RADIO_TECHNOLOGY_IS95A) &&
267              (mNewRilRadioTechnology <= ServiceState.RIL_RADIO_TECHNOLOGY_EVDO_A));
268
269         if (DBG) {
270             log("pollStateDone:"
271                 + " hasRegistered=" + hasRegistered
272                 + " hasDeegistered=" + hasDeregistered
273                 + " hasCdmaDataConnectionAttached=" + hasCdmaDataConnectionAttached
274                 + " hasCdmaDataConnectionDetached=" + hasCdmaDataConnectionDetached
275                 + " hasCdmaDataConnectionChanged=" + hasCdmaDataConnectionChanged
276                 + " hasRadioTechnologyChanged = " + hasRadioTechnologyChanged
277                 + " hasChanged=" + hasChanged
278                 + " hasRoamingOn=" + hasRoamingOn
279                 + " hasRoamingOff=" + hasRoamingOff
280                 + " hasLocationChanged=" + hasLocationChanged
281                 + " has4gHandoff = " + has4gHandoff
282                 + " hasMultiApnSupport=" + hasMultiApnSupport
283                 + " hasLostMultiApnSupport=" + hasLostMultiApnSupport);
284         }
285         // Add an event log when connection state changes
286         if (ss.getState() != newSS.getState()
287                 || mDataConnectionState != mNewDataConnectionState) {
288             EventLog.writeEvent(EventLogTags.CDMA_SERVICE_STATE_CHANGE, ss.getState(),
289                     mDataConnectionState, newSS.getState(), mNewDataConnectionState);
290         }
291
292         ServiceState tss;
293         tss = ss;
294         ss = newSS;
295         newSS = tss;
296         // clean slate for next time
297         newSS.setStateOutOfService();
298         mLteSS.setStateOutOfService();
299
300         if ((hasMultiApnSupport)
301                 && (phone.mDataConnectionTracker instanceof CdmaDataConnectionTracker)) {
302             if (DBG) log("GsmDataConnectionTracker Created");
303             phone.mDataConnectionTracker.dispose();
304             phone.mDataConnectionTracker = new GsmDataConnectionTracker(mCdmaLtePhone);
305         }
306
307         if ((hasLostMultiApnSupport)
308                 && (phone.mDataConnectionTracker instanceof GsmDataConnectionTracker)) {
309             if (DBG)log("GsmDataConnectionTracker disposed");
310             phone.mDataConnectionTracker.dispose();
311             phone.mDataConnectionTracker = new CdmaDataConnectionTracker(phone);
312         }
313
314         CdmaCellLocation tcl = cellLoc;
315         cellLoc = newCellLoc;
316         newCellLoc = tcl;
317
318         mDataConnectionState = mNewDataConnectionState;
319         mRilRadioTechnology = mNewRilRadioTechnology;
320         mNewRilRadioTechnology = 0;
321
322         newSS.setStateOutOfService(); // clean slate for next time
323
324         if (hasRadioTechnologyChanged) {
325             phone.setSystemProperty(TelephonyProperties.PROPERTY_DATA_NETWORK_TYPE,
326                     ServiceState.rilRadioTechnologyToString(mRilRadioTechnology));
327         }
328
329         if (hasRegistered) {
330             mNetworkAttachedRegistrants.notifyRegistrants();
331         }
332
333         if (hasChanged) {
334             if (phone.isEriFileLoaded()) {
335                 String eriText;
336                 // Now the CDMAPhone sees the new ServiceState so it can get the
337                 // new ERI text
338                 if (ss.getState() == ServiceState.STATE_IN_SERVICE) {
339                     eriText = phone.getCdmaEriText();
340                 } else if (ss.getState() == ServiceState.STATE_POWER_OFF) {
341                     eriText = (mIccRecords != null) ? mIccRecords.getServiceProviderName() : null;
342                     if (TextUtils.isEmpty(eriText)) {
343                         // Sets operator alpha property by retrieving from
344                         // build-time system property
345                         eriText = SystemProperties.get("ro.cdma.home.operator.alpha");
346                     }
347                 } else {
348                     // Note that ServiceState.STATE_OUT_OF_SERVICE is valid used
349                     // for mRegistrationState 0,2,3 and 4
350                     eriText = phone.getContext()
351                             .getText(com.android.internal.R.string.roamingTextSearching).toString();
352                 }
353                 ss.setOperatorAlphaLong(eriText);
354             }
355
356             if (mIccCard != null && mIccCard.getState() == IccCardConstants.State.READY &&
357                     mIccRecords != null) {
358                 // SIM is found on the device. If ERI roaming is OFF, and SID/NID matches
359                 // one configfured in SIM, use operator name  from CSIM record.
360                 boolean showSpn =
361                     ((CdmaLteUiccRecords)mIccRecords).getCsimSpnDisplayCondition();
362                 int iconIndex = ss.getCdmaEriIconIndex();
363
364                 if (showSpn && (iconIndex == EriInfo.ROAMING_INDICATOR_OFF) &&
365                     isInHomeSidNid(ss.getSystemId(), ss.getNetworkId()) &&
366                     mIccRecords != null) {
367                     ss.setOperatorAlphaLong(mIccRecords.getServiceProviderName());
368                 }
369             }
370
371             String operatorNumeric;
372
373             phone.setSystemProperty(TelephonyProperties.PROPERTY_OPERATOR_ALPHA,
374                     ss.getOperatorAlphaLong());
375
376             String prevOperatorNumeric =
377                     SystemProperties.get(TelephonyProperties.PROPERTY_OPERATOR_NUMERIC, "");
378             operatorNumeric = ss.getOperatorNumeric();
379             phone.setSystemProperty(TelephonyProperties.PROPERTY_OPERATOR_NUMERIC, operatorNumeric);
380
381             if (operatorNumeric == null) {
382                 if (DBG) log("operatorNumeric is null");
383                 phone.setSystemProperty(TelephonyProperties.PROPERTY_OPERATOR_ISO_COUNTRY, "");
384                 mGotCountryCode = false;
385             } else {
386                 String isoCountryCode = "";
387                 String mcc = operatorNumeric.substring(0, 3);
388                 try {
389                     isoCountryCode = MccTable.countryCodeForMcc(Integer.parseInt(operatorNumeric
390                             .substring(0, 3)));
391                 } catch (NumberFormatException ex) {
392                     loge("countryCodeForMcc error" + ex);
393                 } catch (StringIndexOutOfBoundsException ex) {
394                     loge("countryCodeForMcc error" + ex);
395                 }
396
397                 phone.setSystemProperty(TelephonyProperties.PROPERTY_OPERATOR_ISO_COUNTRY,
398                         isoCountryCode);
399                 mGotCountryCode = true;
400
401                 if (shouldFixTimeZoneNow(phone, operatorNumeric, prevOperatorNumeric,
402                         mNeedFixZone)) {
403                     fixTimeZone(isoCountryCode);
404                 }
405             }
406
407             phone.setSystemProperty(TelephonyProperties.PROPERTY_OPERATOR_ISROAMING,
408                     ss.getRoaming() ? "true" : "false");
409
410             updateSpnDisplay();
411             phone.notifyServiceStateChanged(ss);
412         }
413
414         if (hasCdmaDataConnectionAttached || has4gHandoff) {
415             mAttachedRegistrants.notifyRegistrants();
416         }
417
418         if (hasCdmaDataConnectionDetached) {
419             mDetachedRegistrants.notifyRegistrants();
420         }
421
422         if ((hasCdmaDataConnectionChanged || hasRadioTechnologyChanged)) {
423             phone.notifyDataConnection(null);
424         }
425
426         if (hasRoamingOn) {
427             mRoamingOnRegistrants.notifyRegistrants();
428         }
429
430         if (hasRoamingOff) {
431             mRoamingOffRegistrants.notifyRegistrants();
432         }
433
434         if (hasLocationChanged) {
435             phone.notifyLocationChanged();
436         }
437     }
438
439     @Override
440     protected void onSignalStrengthResult(AsyncResult ar, PhoneBase phone, boolean isGsm) {
441         if (mRilRadioTechnology == ServiceState.RIL_RADIO_TECHNOLOGY_LTE) {
442             isGsm = true;
443         }
444         super.onSignalStrengthResult(ar, phone, isGsm);
445     }
446
447     @Override
448     public boolean isConcurrentVoiceAndDataAllowed() {
449         // Note: it needs to be confirmed which CDMA network types
450         // can support voice and data calls concurrently.
451         // For the time-being, the return value will be false.
452         return (mRilRadioTechnology == ServiceState.RIL_RADIO_TECHNOLOGY_LTE);
453     }
454
455     /**
456      * Check whether the specified SID and NID pair appears in the HOME SID/NID list
457      * read from NV or SIM.
458      *
459      * @return true if provided sid/nid pair belongs to operator's home network.
460      */
461     private boolean isInHomeSidNid(int sid, int nid) {
462         // if SID/NID is not available, assume this is home network.
463         if (isSidsAllZeros()) return true;
464
465         // length of SID/NID shold be same
466         if (mHomeSystemId.length != mHomeNetworkId.length) return true;
467
468         if (sid == 0) return true;
469
470         for (int i = 0; i < mHomeSystemId.length; i++) {
471             // Use SID only if NID is a reserved value.
472             // SID 0 and NID 0 and 65535 are reserved. (C.0005 2.6.5.2)
473             if ((mHomeSystemId[i] == sid) &&
474                 ((mHomeNetworkId[i] == 0) || (mHomeNetworkId[i] == 65535) ||
475                  (nid == 0) || (nid == 65535) || (mHomeNetworkId[i] == nid))) {
476                 return true;
477             }
478         }
479         // SID/NID are not in the list. So device is not in home network
480         return false;
481     }
482
483     @Override
484     protected void log(String s) {
485         Log.d(LOG_TAG, "[CdmaLteSST] " + s);
486     }
487
488     @Override
489     protected void loge(String s) {
490         Log.e(LOG_TAG, "[CdmaLteSST] " + s);
491     }
492
493     @Override
494     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
495         pw.println("CdmaLteServiceStateTracker extends:");
496         super.dump(fd, pw, args);
497         pw.println(" mCdmaLtePhone=" + mCdmaLtePhone);
498         pw.println(" mLteSS=" + mLteSS);
499     }
500 }