OSDN Git Service

am 0fbe1dfb: Merge "cherrypick from master: Change-Id: I169749dc594ca1d79a802db4c53ec...
[android-x86/frameworks-base.git] / telephony / 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.TelephonyProperties;
20 import com.android.internal.telephony.MccTable;
21 import com.android.internal.telephony.EventLogTags;
22 import com.android.internal.telephony.RILConstants;
23
24 import android.content.Intent;
25 import android.telephony.SignalStrength;
26 import android.telephony.ServiceState;
27 import android.telephony.cdma.CdmaCellLocation;
28 import android.os.AsyncResult;
29 import android.os.Message;
30 import android.provider.Telephony.Intents;
31
32 import android.text.TextUtils;
33 import android.util.Log;
34 import android.util.EventLog;
35
36 import com.android.internal.telephony.gsm.GsmDataConnectionTracker;
37
38 public class CdmaLteServiceStateTracker extends CdmaServiceStateTracker {
39     CDMALTEPhone mCdmaLtePhone;
40
41     private ServiceState  mLteSS;  // The last LTE state from Voice Registration
42     private String mCurrentSpn = null;
43
44     public CdmaLteServiceStateTracker(CDMALTEPhone phone) {
45         super(phone);
46         cm.registerForSIMReady(this, EVENT_SIM_READY, null);
47         mCdmaLtePhone = phone;
48
49         mLteSS = new ServiceState();
50         if (DBG) log("CdmaLteServiceStateTracker Constructors");
51     }
52
53     @Override
54     public void dispose() {
55         cm.unregisterForSIMReady(this);
56         super.dispose();
57     }
58
59     @Override
60     public void handleMessage(Message msg) {
61         AsyncResult ar;
62         int[] ints;
63         String[] strings;
64         switch (msg.what) {
65         case EVENT_POLL_STATE_GPRS:
66             if (DBG) log("handleMessage EVENT_POLL_STATE_GPRS");
67             ar = (AsyncResult)msg.obj;
68             handlePollStateResult(msg.what, ar);
69             break;
70         case EVENT_SIM_READY:
71             if (DBG) log("handleMessage EVENT_SIM_READY");
72             isSubscriptionFromRuim = false;
73             // Register SIM_RECORDS_LOADED dynamically.
74             // This is to avoid confilct with RUIM_READY scenario)
75             phone.mIccRecords.registerForRecordsLoaded(this, EVENT_SIM_RECORDS_LOADED, null);
76             pollState();
77             // Signal strength polling stops when radio is off.
78             queueNextSignalStrengthPoll();
79
80             // load ERI file
81             phone.prepareEri();
82             break;
83         case EVENT_SIM_RECORDS_LOADED:
84             CdmaLteUiccRecords sim = (CdmaLteUiccRecords)phone.mIccRecords;
85             if ((sim != null) && sim.isProvisioned()) {
86                 mMdn = sim.getMdn();
87                 mMin = sim.getMin();
88                 parseSidNid(sim.getSid(), sim.getNid());
89                 mPrlVersion = sim.getPrlVersion();;
90                 mIsMinInfoReady = true;
91                 updateOtaspState();
92             }
93             // SID/NID/PRL is loaded. Poll service state
94             // again to update to the roaming state with
95             // the latest variables.
96             pollState();
97             break;
98         default:
99             super.handleMessage(msg);
100         }
101     }
102
103     /**
104      * Set the cdmaSS for EVENT_POLL_STATE_REGISTRATION_CDMA
105      */
106     @Override
107     protected void setCdmaTechnology(int radioTechnology) {
108         // Called on voice registration state response.
109         // Just record new CDMA radio technology
110         newSS.setRadioTechnology(radioTechnology);
111     }
112
113     /**
114      * Handle the result of one of the pollState()-related requests
115      */
116     @Override
117     protected void handlePollStateResultMessage(int what, AsyncResult ar) {
118         if (what == EVENT_POLL_STATE_GPRS) {
119             if (DBG) log("handlePollStateResultMessage: EVENT_POLL_STATE_GPRS");
120             String states[] = (String[])ar.result;
121
122             int type = 0;
123             int regState = -1;
124             if (states.length > 0) {
125                 try {
126                     regState = Integer.parseInt(states[0]);
127
128                     // states[3] (if present) is the current radio technology
129                     if (states.length >= 4 && states[3] != null) {
130                         type = Integer.parseInt(states[3]);
131                     }
132                 } catch (NumberFormatException ex) {
133                     loge("handlePollStateResultMessage: error parsing GprsRegistrationState: "
134                                     + ex);
135                 }
136             }
137
138             // Not sure if this is needed in CDMALTE phone.
139             // mDataRoaming = regCodeIsRoaming(regState);
140             mLteSS.setRadioTechnology(type);
141             mLteSS.setState(regCodeToServiceState(regState));
142         } else {
143             super.handlePollStateResultMessage(what, ar);
144         }
145     }
146
147     @Override
148     protected void setSignalStrengthDefaultValues() {
149         mSignalStrength = new SignalStrength(99, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, false);
150     }
151
152     @Override
153     protected void pollState() {
154         pollingContext = new int[1];
155         pollingContext[0] = 0;
156
157         switch (cm.getRadioState()) {
158             case RADIO_UNAVAILABLE:
159                 newSS.setStateOutOfService();
160                 newCellLoc.setStateInvalid();
161                 setSignalStrengthDefaultValues();
162                 mGotCountryCode = false;
163
164                 pollStateDone();
165                 break;
166
167             case RADIO_OFF:
168                 newSS.setStateOff();
169                 newCellLoc.setStateInvalid();
170                 setSignalStrengthDefaultValues();
171                 mGotCountryCode = false;
172
173                 pollStateDone();
174                 break;
175
176             default:
177                 // Issue all poll-related commands at once, then count
178                 // down the responses which are allowed to arrive
179                 // out-of-order.
180
181                 pollingContext[0]++;
182                 // RIL_REQUEST_OPERATOR is necessary for CDMA
183                 cm.getOperator(obtainMessage(EVENT_POLL_STATE_OPERATOR_CDMA, pollingContext));
184
185                 pollingContext[0]++;
186                 // RIL_REQUEST_VOICE_REGISTRATION_STATE is necessary for CDMA
187                 cm.getVoiceRegistrationState(obtainMessage(EVENT_POLL_STATE_REGISTRATION_CDMA,
188                         pollingContext));
189
190                 int networkMode = android.provider.Settings.Secure.getInt(phone.getContext()
191                         .getContentResolver(),
192                         android.provider.Settings.Secure.PREFERRED_NETWORK_MODE,
193                         RILConstants.PREFERRED_NETWORK_MODE);
194                 if (DBG) log("pollState: network mode here is = " + networkMode);
195                 if ((networkMode == RILConstants.NETWORK_MODE_GLOBAL)
196                         || (networkMode == RILConstants.NETWORK_MODE_LTE_ONLY)) {
197                     pollingContext[0]++;
198                     // RIL_REQUEST_DATA_REGISTRATION_STATE
199                     cm.getDataRegistrationState(obtainMessage(EVENT_POLL_STATE_GPRS,
200                                                 pollingContext));
201                 }
202                 break;
203         }
204     }
205
206     @Override
207     protected void pollStateDone() {
208         // determine data NetworkType from both LET and CDMA SS
209         if (mLteSS.getState() == ServiceState.STATE_IN_SERVICE) {
210             //in LTE service
211             newNetworkType = mLteSS.getRadioTechnology();
212             mNewDataConnectionState = mLteSS.getState();
213             newSS.setRadioTechnology(newNetworkType);
214             log("pollStateDone LTE/eHRPD STATE_IN_SERVICE newNetworkType = " + newNetworkType);
215         } else {
216             // LTE out of service, get CDMA Service State
217             newNetworkType = newSS.getRadioTechnology();
218             mNewDataConnectionState = radioTechnologyToDataServiceState(newNetworkType);
219             log("pollStateDone CDMA STATE_IN_SERVICE newNetworkType = " + newNetworkType +
220                 " mNewDataConnectionState = " + mNewDataConnectionState);
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 hasNetworkTypeChanged = networkType != newNetworkType;
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                 ((networkType == ServiceState.RADIO_TECHNOLOGY_LTE) &&
254                  (newNetworkType == ServiceState.RADIO_TECHNOLOGY_EHRPD)) ||
255                 ((networkType == ServiceState.RADIO_TECHNOLOGY_EHRPD) &&
256                  (newNetworkType == ServiceState.RADIO_TECHNOLOGY_LTE));
257
258         boolean hasMultiApnSupport =
259                 (((newNetworkType == ServiceState.RADIO_TECHNOLOGY_LTE) ||
260                   (newNetworkType == ServiceState.RADIO_TECHNOLOGY_EHRPD)) &&
261                  ((networkType != ServiceState.RADIO_TECHNOLOGY_LTE) &&
262                   (networkType != ServiceState.RADIO_TECHNOLOGY_EHRPD)));
263
264         boolean hasLostMultiApnSupport =
265             ((newNetworkType >= ServiceState.RADIO_TECHNOLOGY_IS95A) &&
266              (newNetworkType <= ServiceState.RADIO_TECHNOLOGY_EVDO_A));
267
268         if (DBG) {
269             log("pollStateDone:"
270                 + " hasRegistered=" + hasRegistered
271                 + " hasDeegistered=" + hasDeregistered
272                 + " hasCdmaDataConnectionAttached=" + hasCdmaDataConnectionAttached
273                 + " hasCdmaDataConnectionDetached=" + hasCdmaDataConnectionDetached
274                 + " hasCdmaDataConnectionChanged=" + hasCdmaDataConnectionChanged
275                 + " hasNetworkTypeChanged = " + hasNetworkTypeChanged
276                 + " hasChanged=" + hasChanged
277                 + " hasRoamingOn=" + hasRoamingOn
278                 + " hasRoamingOff=" + hasRoamingOff
279                 + " hasLocationChanged=" + hasLocationChanged
280                 + " has4gHandoff = " + has4gHandoff
281                 + " hasMultiApnSupport=" + hasMultiApnSupport
282                 + " hasLostMultiApnSupport=" + hasLostMultiApnSupport);
283         }
284         // Add an event log when connection state changes
285         if (ss.getState() != newSS.getState()
286                 || mDataConnectionState != mNewDataConnectionState) {
287             EventLog.writeEvent(EventLogTags.CDMA_SERVICE_STATE_CHANGE, ss.getState(),
288                     mDataConnectionState, newSS.getState(), mNewDataConnectionState);
289         }
290
291         ServiceState tss;
292         tss = ss;
293         ss = newSS;
294         newSS = tss;
295         // clean slate for next time
296         newSS.setStateOutOfService();
297         mLteSS.setStateOutOfService();
298
299         if ((hasMultiApnSupport)
300                 && (phone.mDataConnectionTracker instanceof CdmaDataConnectionTracker)) {
301             if (DBG) log("GsmDataConnectionTracker Created");
302             phone.mDataConnectionTracker.dispose();
303             phone.mDataConnectionTracker = new GsmDataConnectionTracker(mCdmaLtePhone);
304         }
305
306         if ((hasLostMultiApnSupport)
307                 && (phone.mDataConnectionTracker instanceof GsmDataConnectionTracker)) {
308             if (DBG)log("GsmDataConnectionTracker disposed");
309             phone.mDataConnectionTracker.dispose();
310             phone.mDataConnectionTracker = new CdmaDataConnectionTracker(phone);
311         }
312
313         CdmaCellLocation tcl = cellLoc;
314         cellLoc = newCellLoc;
315         newCellLoc = tcl;
316
317         mDataConnectionState = mNewDataConnectionState;
318         networkType = newNetworkType;
319
320         newSS.setStateOutOfService(); // clean slate for next time
321
322         if (hasNetworkTypeChanged) {
323             phone.setSystemProperty(TelephonyProperties.PROPERTY_DATA_NETWORK_TYPE,
324                     ServiceState.radioTechnologyToString(networkType));
325         }
326
327         if (hasRegistered) {
328             mNetworkAttachedRegistrants.notifyRegistrants();
329         }
330
331         if (hasChanged) {
332             if (phone.isEriFileLoaded()) {
333                 String eriText;
334                 // Now the CDMAPhone sees the new ServiceState so it can get the
335                 // new ERI text
336                 if (ss.getState() == ServiceState.STATE_IN_SERVICE) {
337                     eriText = phone.getCdmaEriText();
338                 } else {
339                     // Note that ServiceState.STATE_OUT_OF_SERVICE is valid used
340                     // for
341                     // mRegistrationState 0,2,3 and 4
342                     eriText = phone.getContext()
343                             .getText(com.android.internal.R.string.roamingTextSearching).toString();
344                 }
345                 ss.setOperatorAlphaLong(eriText);
346             }
347
348             String operatorNumeric;
349
350             phone.setSystemProperty(TelephonyProperties.PROPERTY_OPERATOR_ALPHA,
351                     ss.getOperatorAlphaLong());
352
353             operatorNumeric = ss.getOperatorNumeric();
354             phone.setSystemProperty(TelephonyProperties.PROPERTY_OPERATOR_NUMERIC, operatorNumeric);
355
356             if (operatorNumeric == null) {
357                 phone.setSystemProperty(TelephonyProperties.PROPERTY_OPERATOR_ISO_COUNTRY, "");
358             } else {
359                 String isoCountryCode = "";
360                 try {
361                     isoCountryCode = MccTable.countryCodeForMcc(Integer.parseInt(operatorNumeric
362                             .substring(0, 3)));
363                 } catch (NumberFormatException ex) {
364                     loge("countryCodeForMcc error" + ex);
365                 } catch (StringIndexOutOfBoundsException ex) {
366                     loge("countryCodeForMcc error" + ex);
367                 }
368
369                 phone.setSystemProperty(TelephonyProperties.PROPERTY_OPERATOR_ISO_COUNTRY,
370                         isoCountryCode);
371                 mGotCountryCode = true;
372                 if (mNeedFixZone) {
373                     fixTimeZone(isoCountryCode);
374                 }
375             }
376
377             phone.setSystemProperty(TelephonyProperties.PROPERTY_OPERATOR_ISROAMING,
378                     ss.getRoaming() ? "true" : "false");
379
380             updateSpnDisplay();
381             phone.notifyServiceStateChanged(ss);
382         }
383
384         if (hasCdmaDataConnectionAttached) {
385             mAttachedRegistrants.notifyRegistrants();
386         }
387
388         if (hasCdmaDataConnectionDetached) {
389             mDetachedRegistrants.notifyRegistrants();
390         }
391
392         if ((hasCdmaDataConnectionChanged || hasNetworkTypeChanged)) {
393             phone.notifyDataConnection();
394         }
395
396         if (hasRoamingOn) {
397             mRoamingOnRegistrants.notifyRegistrants();
398         }
399
400         if (hasRoamingOff) {
401             mRoamingOffRegistrants.notifyRegistrants();
402         }
403
404         if (hasLocationChanged) {
405             phone.notifyLocationChanged();
406         }
407     }
408
409     @Override
410     protected void onSignalStrengthResult(AsyncResult ar) {
411         SignalStrength oldSignalStrength = mSignalStrength;
412
413         if (ar.exception != null) {
414             // Most likely radio is resetting/disconnected change to default
415             // values.
416             setSignalStrengthDefaultValues();
417         } else {
418             int[] ints = (int[])ar.result;
419             int lteCqi = 99, lteRsrp = -1;
420             int lteRssi = 99;
421             int offset = 2;
422             int cdmaDbm = (ints[offset] > 0) ? -ints[offset] : -120;
423             int cdmaEcio = (ints[offset + 1] > 0) ? -ints[offset + 1] : -160;
424             int evdoRssi = (ints[offset + 2] > 0) ? -ints[offset + 2] : -120;
425             int evdoEcio = (ints[offset + 3] > 0) ? -ints[offset + 3] : -1;
426             int evdoSnr = ((ints[offset + 4] > 0) && (ints[offset + 4] <= 8)) ? ints[offset + 4]
427                     : -1;
428             if (networkType == ServiceState.RADIO_TECHNOLOGY_LTE) {
429                 lteRssi = (ints[offset + 5] >= 0) ? ints[offset + 5] : 99;
430                 lteRsrp = (ints[offset + 6] < 0) ? ints[offset + 6] : -1;
431                 lteCqi = (ints[offset + 7] >= 0) ? ints[offset + 7] : 99;
432             }
433
434             if (networkType != ServiceState.RADIO_TECHNOLOGY_LTE) {
435                 mSignalStrength = new SignalStrength(99, -1, cdmaDbm, cdmaEcio, evdoRssi, evdoEcio,
436                         evdoSnr, false);
437             } else {
438                 mSignalStrength = new SignalStrength(99, -1, cdmaDbm, cdmaEcio, evdoRssi, evdoEcio,
439                         evdoSnr, lteRssi, lteRsrp, -1, -1, lteCqi, true);
440             }
441         }
442
443         try {
444             phone.notifySignalStrength();
445         } catch (NullPointerException ex) {
446             loge("onSignalStrengthResult() Phone already destroyed: " + ex
447                     + "SignalStrength not notified");
448         }
449     }
450
451     @Override
452     public boolean isConcurrentVoiceAndDataAllowed() {
453         // Note: it needs to be confirmed which CDMA network types
454         // can support voice and data calls concurrently.
455         // For the time-being, the return value will be false.
456         // return (networkType >= ServiceState.RADIO_TECHNOLOGY_LTE);
457         return false;
458     }
459
460     /**
461      * Returns OTASP_NOT_NEEDED as its not needed for LTE
462      */
463     @Override
464     int getOtasp() {
465         int provisioningState = OTASP_NOT_NEEDED;
466         if (DBG) log("getOtasp: state=" + provisioningState);
467         return provisioningState;
468     }
469
470     @Override
471     protected void updateSpnDisplay() {
472         // mOperatorAlphaLong contains the ERI text
473         String plmn = ss.getOperatorAlphaLong();
474
475         boolean showSpn = false;
476         String spn = null;
477         if (cm.getSimState().isSIMReady()) {
478             // SIM is found on the device. Read the operator name from the card.
479             showSpn = ((CdmaLteUiccRecords)phone.mIccRecords).getCsimSpnDisplayCondition();
480             spn = phone.mIccRecords.getServiceProviderName();
481
482             // double check we are not printing identicall test
483             if (TextUtils.equals(plmn, spn)) showSpn = false;
484         }
485
486         if (!TextUtils.equals(plmn, mCurPlmn) ||
487             !TextUtils.equals(spn, mCurrentSpn)) {
488             boolean showPlmn = plmn != null;
489             if (DBG) {
490                 log(String.format("updateSpnDisplay: changed sending intent" +
491                                   " showPlmn='%b' plmn='%s' showSpn='%b' spn='%s'",
492                                   showPlmn, plmn, showSpn, spn));
493             }
494             Intent intent = new Intent(Intents.SPN_STRINGS_UPDATED_ACTION);
495             intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
496             intent.putExtra(Intents.EXTRA_SHOW_SPN, showSpn);
497             intent.putExtra(Intents.EXTRA_SPN, spn);
498             intent.putExtra(Intents.EXTRA_SHOW_PLMN, showPlmn);
499             intent.putExtra(Intents.EXTRA_PLMN, plmn);
500             phone.getContext().sendStickyBroadcast(intent);
501         }
502
503         mCurPlmn = plmn;
504         mCurrentSpn = spn;
505     }
506
507     @Override
508     protected void log(String s) {
509         Log.d(LOG_TAG, "[CdmaLteSST] " + s);
510     }
511
512     @Override
513     protected void loge(String s) {
514         Log.e(LOG_TAG, "[CdmaLteSST] " + s);
515     }
516 }