| /* |
| * Copyright (C) 2012 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package com.android.internal.telephony.cdma; |
| |
| import android.app.AlarmManager; |
| import android.content.ContentResolver; |
| import android.content.Context; |
| import android.content.Intent; |
| import android.database.ContentObserver; |
| import android.os.AsyncResult; |
| import android.os.Build; |
| import android.os.Handler; |
| import android.os.Message; |
| import android.os.PowerManager; |
| import android.os.Registrant; |
| import android.os.RegistrantList; |
| import android.os.SystemClock; |
| import android.os.SystemProperties; |
| import android.os.UserHandle; |
| import android.provider.Settings; |
| import android.provider.Settings.SettingNotFoundException; |
| import android.telephony.CellInfo; |
| import android.telephony.CellInfoCdma; |
| import android.telephony.Rlog; |
| import android.telephony.ServiceState; |
| import android.telephony.SignalStrength; |
| import android.telephony.TelephonyManager; |
| import android.telephony.SubscriptionManager; |
| import android.telephony.cdma.CdmaCellLocation; |
| import android.text.TextUtils; |
| import android.util.EventLog; |
| import android.util.TimeUtils; |
| |
| import com.android.internal.telephony.CommandException; |
| import com.android.internal.telephony.CommandsInterface; |
| import com.android.internal.telephony.CommandsInterface.RadioState; |
| import com.android.internal.telephony.EventLogTags; |
| import com.android.internal.telephony.MccTable; |
| import com.android.internal.telephony.Phone; |
| import com.android.internal.telephony.PhoneConstants; |
| import com.android.internal.telephony.PhoneFactory; |
| import com.android.internal.telephony.ServiceStateTracker; |
| import com.android.internal.telephony.TelephonyIntents; |
| import com.android.internal.telephony.TelephonyProperties; |
| import com.android.internal.telephony.dataconnection.DcTrackerBase; |
| import com.android.internal.telephony.uicc.UiccCardApplication; |
| import com.android.internal.telephony.uicc.UiccController; |
| import com.android.internal.telephony.HbpcdUtils; |
| |
| import java.io.FileDescriptor; |
| import java.io.PrintWriter; |
| import java.util.Arrays; |
| import java.util.Calendar; |
| import java.util.Date; |
| import java.util.List; |
| import java.util.TimeZone; |
| |
| /** |
| * {@hide} |
| */ |
| public class CdmaServiceStateTracker extends ServiceStateTracker { |
| static final String LOG_TAG = "CdmaSST"; |
| |
| CDMAPhone mPhone; |
| CdmaCellLocation mCellLoc; |
| CdmaCellLocation mNewCellLoc; |
| |
| // Min values used to by getOtasp() |
| private static final String UNACTIVATED_MIN2_VALUE = "000000"; |
| private static final String UNACTIVATED_MIN_VALUE = "1111110111"; |
| |
| private static final int MS_PER_HOUR = 60 * 60 * 1000; |
| |
| // Current Otasp value |
| int mCurrentOtaspMode = OTASP_UNINITIALIZED; |
| |
| /** if time between NITZ updates is less than mNitzUpdateSpacing the update may be ignored. */ |
| private static final int NITZ_UPDATE_SPACING_DEFAULT = 1000 * 60 * 10; |
| private int mNitzUpdateSpacing = SystemProperties.getInt("ro.nitz_update_spacing", |
| NITZ_UPDATE_SPACING_DEFAULT); |
| |
| /** If mNitzUpdateSpacing hasn't been exceeded but update is > mNitzUpdate do the update */ |
| private static final int NITZ_UPDATE_DIFF_DEFAULT = 2000; |
| private int mNitzUpdateDiff = SystemProperties.getInt("ro.nitz_update_diff", |
| NITZ_UPDATE_DIFF_DEFAULT); |
| |
| private boolean mCdmaRoaming = false; |
| private int mRoamingIndicator; |
| private boolean mIsInPrl; |
| private int mDefaultRoamingIndicator; |
| |
| /** |
| * Initially assume no data connection. |
| */ |
| protected int mRegistrationState = -1; |
| protected RegistrantList mCdmaForSubscriptionInfoReadyRegistrants = new RegistrantList(); |
| |
| /** |
| * Sometimes we get the NITZ time before we know what country we |
| * are in. Keep the time zone information from the NITZ string so |
| * we can fix the time zone once know the country. |
| */ |
| protected boolean mNeedFixZone = false; |
| private int mZoneOffset; |
| private boolean mZoneDst; |
| private long mZoneTime; |
| protected boolean mGotCountryCode = false; |
| String mSavedTimeZone; |
| long mSavedTime; |
| long mSavedAtTime; |
| |
| /** Wake lock used while setting time of day. */ |
| private PowerManager.WakeLock mWakeLock; |
| private static final String WAKELOCK_TAG = "ServiceStateTracker"; |
| |
| /** Contains the name of the registered network in CDMA (either ONS or ERI text). */ |
| protected String mCurPlmn = null; |
| |
| protected String mMdn; |
| protected int mHomeSystemId[] = null; |
| protected int mHomeNetworkId[] = null; |
| protected String mMin; |
| protected String mPrlVersion; |
| protected boolean mIsMinInfoReady = false; |
| |
| private boolean mIsEriTextLoaded = false; |
| protected boolean mIsSubscriptionFromRuim = false; |
| private CdmaSubscriptionSourceManager mCdmaSSM; |
| |
| protected static final String INVALID_MCC = "000"; |
| protected static final String DEFAULT_MNC = "00"; |
| |
| protected HbpcdUtils mHbpcdUtils = null; |
| |
| /* Used only for debugging purposes. */ |
| private String mRegistrationDeniedReason; |
| |
| private ContentResolver mCr; |
| private String mCurrentCarrier = null; |
| |
| private ContentObserver mAutoTimeObserver = new ContentObserver(new Handler()) { |
| @Override |
| public void onChange(boolean selfChange) { |
| if (DBG) log("Auto time state changed"); |
| revertToNitzTime(); |
| } |
| }; |
| |
| private ContentObserver mAutoTimeZoneObserver = new ContentObserver(new Handler()) { |
| @Override |
| public void onChange(boolean selfChange) { |
| if (DBG) log("Auto time zone state changed"); |
| revertToNitzTimeZone(); |
| } |
| }; |
| |
| public CdmaServiceStateTracker(CDMAPhone phone) { |
| this(phone, new CellInfoCdma()); |
| } |
| |
| protected CdmaServiceStateTracker(CDMAPhone phone, CellInfo cellInfo) { |
| super(phone, phone.mCi, cellInfo); |
| |
| mPhone = phone; |
| mCr = phone.getContext().getContentResolver(); |
| mCellLoc = new CdmaCellLocation(); |
| mNewCellLoc = new CdmaCellLocation(); |
| |
| mCdmaSSM = CdmaSubscriptionSourceManager.getInstance(phone.getContext(), mCi, this, |
| EVENT_CDMA_SUBSCRIPTION_SOURCE_CHANGED, null); |
| mIsSubscriptionFromRuim = (mCdmaSSM.getCdmaSubscriptionSource() == |
| CdmaSubscriptionSourceManager.SUBSCRIPTION_FROM_RUIM); |
| |
| PowerManager powerManager = |
| (PowerManager)phone.getContext().getSystemService(Context.POWER_SERVICE); |
| mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_TAG); |
| |
| mCi.registerForRadioStateChanged(this, EVENT_RADIO_STATE_CHANGED, null); |
| |
| mCi.registerForVoiceNetworkStateChanged(this, EVENT_NETWORK_STATE_CHANGED_CDMA, null); |
| mCi.setOnNITZTime(this, EVENT_NITZ_TIME, null); |
| |
| mCi.registerForCdmaPrlChanged(this, EVENT_CDMA_PRL_VERSION_CHANGED, null); |
| phone.registerForEriFileLoaded(this, EVENT_ERI_FILE_LOADED, null); |
| mCi.registerForCdmaOtaProvision(this,EVENT_OTA_PROVISION_STATUS_CHANGE, null); |
| |
| // System setting property AIRPLANE_MODE_ON is set in Settings. |
| int airplaneMode = Settings.Global.getInt(mCr, Settings.Global.AIRPLANE_MODE_ON, 0); |
| mDesiredPowerState = ! (airplaneMode > 0); |
| |
| mCr.registerContentObserver( |
| Settings.Global.getUriFor(Settings.Global.AUTO_TIME), true, |
| mAutoTimeObserver); |
| mCr.registerContentObserver( |
| Settings.Global.getUriFor(Settings.Global.AUTO_TIME_ZONE), true, |
| mAutoTimeZoneObserver); |
| setSignalStrengthDefaultValues(); |
| |
| mHbpcdUtils = new HbpcdUtils(phone.getContext()); |
| |
| // Reset OTASP state in case previously set by another service |
| phone.notifyOtaspChanged(OTASP_UNINITIALIZED); |
| } |
| |
| @Override |
| public void dispose() { |
| checkCorrectThread(); |
| log("ServiceStateTracker dispose"); |
| |
| // Unregister for all events. |
| mCi.unregisterForRadioStateChanged(this); |
| mCi.unregisterForVoiceNetworkStateChanged(this); |
| mCi.unregisterForCdmaOtaProvision(this); |
| mPhone.unregisterForEriFileLoaded(this); |
| if (mUiccApplcation != null) {mUiccApplcation.unregisterForReady(this);} |
| if (mIccRecords != null) {mIccRecords.unregisterForRecordsLoaded(this);} |
| mCi.unSetOnNITZTime(this); |
| mCr.unregisterContentObserver(mAutoTimeObserver); |
| mCr.unregisterContentObserver(mAutoTimeZoneObserver); |
| mCdmaSSM.dispose(this); |
| mCi.unregisterForCdmaPrlChanged(this); |
| super.dispose(); |
| } |
| |
| @Override |
| protected void finalize() { |
| if (DBG) log("CdmaServiceStateTracker finalized"); |
| } |
| |
| /** |
| * Registration point for subscription info ready |
| * @param h handler to notify |
| * @param what what code of message when delivered |
| * @param obj placed in Message.obj |
| */ |
| public void registerForSubscriptionInfoReady(Handler h, int what, Object obj) { |
| Registrant r = new Registrant(h, what, obj); |
| mCdmaForSubscriptionInfoReadyRegistrants.add(r); |
| |
| if (isMinInfoReady()) { |
| r.notifyRegistrant(); |
| } |
| } |
| |
| public void unregisterForSubscriptionInfoReady(Handler h) { |
| mCdmaForSubscriptionInfoReadyRegistrants.remove(h); |
| } |
| |
| /** |
| * Save current source of cdma subscription |
| * @param source - 1 for NV, 0 for RUIM |
| */ |
| private void saveCdmaSubscriptionSource(int source) { |
| log("Storing cdma subscription source: " + source); |
| Settings.Global.putInt(mPhone.getContext().getContentResolver(), |
| Settings.Global.CDMA_SUBSCRIPTION_MODE, |
| source ); |
| log("Read from settings: " + Settings.Global.getInt(mPhone.getContext().getContentResolver(), |
| Settings.Global.CDMA_SUBSCRIPTION_MODE, -1)); |
| } |
| |
| private void getSubscriptionInfoAndStartPollingThreads() { |
| mCi.getCDMASubscription(obtainMessage(EVENT_POLL_STATE_CDMA_SUBSCRIPTION)); |
| |
| // Get Registration Information |
| pollState(); |
| } |
| |
| @Override |
| public void handleMessage (Message msg) { |
| AsyncResult ar; |
| int[] ints; |
| String[] strings; |
| |
| if (!mPhone.mIsTheCurrentActivePhone) { |
| loge("Received message " + msg + "[" + msg.what + "]" + |
| " while being destroyed. Ignoring."); |
| return; |
| } |
| |
| switch (msg.what) { |
| case EVENT_CDMA_SUBSCRIPTION_SOURCE_CHANGED: |
| handleCdmaSubscriptionSource(mCdmaSSM.getCdmaSubscriptionSource()); |
| break; |
| |
| case EVENT_RUIM_READY: |
| int networkType = PhoneFactory.calculatePreferredNetworkType( |
| mPhone.getContext(), mPhone.getPhoneId()); |
| mCi.setPreferredNetworkType(networkType, null); |
| |
| if (mPhone.getLteOnCdmaMode() == PhoneConstants.LTE_ON_CDMA_TRUE) { |
| // Subscription will be read from SIM I/O |
| if (DBG) log("Receive EVENT_RUIM_READY"); |
| pollState(); |
| } else { |
| if (DBG) log("Receive EVENT_RUIM_READY and Send Request getCDMASubscription."); |
| getSubscriptionInfoAndStartPollingThreads(); |
| } |
| |
| // Only support automatic selection mode in CDMA. |
| mCi.getNetworkSelectionMode(obtainMessage(EVENT_POLL_STATE_NETWORK_SELECTION_MODE)); |
| |
| mPhone.prepareEri(); |
| break; |
| |
| case EVENT_NV_READY: |
| updatePhoneObject(); |
| |
| // Only support automatic selection mode in CDMA. |
| mCi.getNetworkSelectionMode(obtainMessage(EVENT_POLL_STATE_NETWORK_SELECTION_MODE)); |
| |
| // For Non-RUIM phones, the subscription information is stored in |
| // Non Volatile. Here when Non-Volatile is ready, we can poll the CDMA |
| // subscription info. |
| getSubscriptionInfoAndStartPollingThreads(); |
| break; |
| |
| case EVENT_RADIO_STATE_CHANGED: |
| if(mCi.getRadioState() == RadioState.RADIO_ON) { |
| handleCdmaSubscriptionSource(mCdmaSSM.getCdmaSubscriptionSource()); |
| |
| // Signal strength polling stops when radio is off. |
| queueNextSignalStrengthPoll(); |
| } |
| // This will do nothing in the 'radio not available' case. |
| setPowerStateToDesired(); |
| pollState(); |
| break; |
| |
| case EVENT_NETWORK_STATE_CHANGED_CDMA: |
| pollState(); |
| break; |
| |
| case EVENT_GET_SIGNAL_STRENGTH: |
| // This callback is called when signal strength is polled |
| // all by itself. |
| |
| if (!(mCi.getRadioState().isOn())) { |
| // Polling will continue when radio turns back on. |
| return; |
| } |
| ar = (AsyncResult) msg.obj; |
| onSignalStrengthResult(ar, false); |
| queueNextSignalStrengthPoll(); |
| |
| break; |
| |
| case EVENT_GET_LOC_DONE_CDMA: |
| ar = (AsyncResult) msg.obj; |
| |
| if (ar.exception == null) { |
| String states[] = (String[])ar.result; |
| int baseStationId = -1; |
| int baseStationLatitude = CdmaCellLocation.INVALID_LAT_LONG; |
| int baseStationLongitude = CdmaCellLocation.INVALID_LAT_LONG; |
| int systemId = -1; |
| int networkId = -1; |
| |
| if (states.length > 9) { |
| try { |
| if (states[4] != null) { |
| baseStationId = Integer.parseInt(states[4]); |
| } |
| if (states[5] != null) { |
| baseStationLatitude = Integer.parseInt(states[5]); |
| } |
| if (states[6] != null) { |
| baseStationLongitude = Integer.parseInt(states[6]); |
| } |
| // Some carriers only return lat-lngs of 0,0 |
| if (baseStationLatitude == 0 && baseStationLongitude == 0) { |
| baseStationLatitude = CdmaCellLocation.INVALID_LAT_LONG; |
| baseStationLongitude = CdmaCellLocation.INVALID_LAT_LONG; |
| } |
| if (states[8] != null) { |
| systemId = Integer.parseInt(states[8]); |
| } |
| if (states[9] != null) { |
| networkId = Integer.parseInt(states[9]); |
| } |
| } catch (NumberFormatException ex) { |
| loge("error parsing cell location data: " + ex); |
| } |
| } |
| |
| mCellLoc.setCellLocationData(baseStationId, baseStationLatitude, |
| baseStationLongitude, systemId, networkId); |
| mPhone.notifyLocationChanged(); |
| } |
| |
| // Release any temporary cell lock, which could have been |
| // acquired to allow a single-shot location update. |
| disableSingleLocationUpdate(); |
| break; |
| |
| case EVENT_POLL_STATE_REGISTRATION_CDMA: |
| case EVENT_POLL_STATE_OPERATOR_CDMA: |
| case EVENT_POLL_STATE_GPRS: |
| ar = (AsyncResult) msg.obj; |
| handlePollStateResult(msg.what, ar); |
| break; |
| |
| case EVENT_POLL_STATE_CDMA_SUBSCRIPTION: // Handle RIL_CDMA_SUBSCRIPTION |
| ar = (AsyncResult) msg.obj; |
| |
| if (ar.exception == null) { |
| String cdmaSubscription[] = (String[])ar.result; |
| if (cdmaSubscription != null && cdmaSubscription.length >= 5) { |
| mMdn = cdmaSubscription[0]; |
| parseSidNid(cdmaSubscription[1], cdmaSubscription[2]); |
| |
| mMin = cdmaSubscription[3]; |
| mPrlVersion = cdmaSubscription[4]; |
| if (DBG) log("GET_CDMA_SUBSCRIPTION: MDN=" + mMdn); |
| |
| mIsMinInfoReady = true; |
| |
| updateOtaspState(); |
| if (!mIsSubscriptionFromRuim && mIccRecords != null) { |
| if (DBG) { |
| log("GET_CDMA_SUBSCRIPTION set imsi in mIccRecords"); |
| } |
| mIccRecords.setImsi(getImsi()); |
| } else { |
| if (DBG) { |
| log("GET_CDMA_SUBSCRIPTION either mIccRecords is null or NV type device" + |
| " - not setting Imsi in mIccRecords"); |
| } |
| } |
| } else { |
| if (DBG) { |
| log("GET_CDMA_SUBSCRIPTION: error parsing cdmaSubscription params num=" |
| + cdmaSubscription.length); |
| } |
| } |
| } |
| break; |
| |
| case EVENT_POLL_SIGNAL_STRENGTH: |
| // Just poll signal strength...not part of pollState() |
| |
| mCi.getSignalStrength(obtainMessage(EVENT_GET_SIGNAL_STRENGTH)); |
| break; |
| |
| case EVENT_NITZ_TIME: |
| ar = (AsyncResult) msg.obj; |
| |
| String nitzString = (String)((Object[])ar.result)[0]; |
| long nitzReceiveTime = ((Long)((Object[])ar.result)[1]).longValue(); |
| |
| setTimeFromNITZString(nitzString, nitzReceiveTime); |
| break; |
| |
| case EVENT_SIGNAL_STRENGTH_UPDATE: |
| // This is a notification from CommandsInterface.setOnSignalStrengthUpdate. |
| |
| ar = (AsyncResult) msg.obj; |
| |
| // The radio is telling us about signal strength changes, |
| // so we don't have to ask it. |
| mDontPollSignalStrength = true; |
| |
| onSignalStrengthResult(ar, false); |
| break; |
| |
| case EVENT_RUIM_RECORDS_LOADED: |
| log("EVENT_RUIM_RECORDS_LOADED: what=" + msg.what); |
| updatePhoneObject(); |
| updateSpnDisplay(); |
| break; |
| |
| case EVENT_LOCATION_UPDATES_ENABLED: |
| ar = (AsyncResult) msg.obj; |
| |
| if (ar.exception == null) { |
| mCi.getVoiceRegistrationState(obtainMessage(EVENT_GET_LOC_DONE_CDMA, null)); |
| } |
| break; |
| |
| case EVENT_ERI_FILE_LOADED: |
| // Repoll the state once the ERI file has been loaded. |
| if (DBG) log("[CdmaServiceStateTracker] ERI file has been loaded, repolling."); |
| pollState(); |
| break; |
| |
| case EVENT_OTA_PROVISION_STATUS_CHANGE: |
| ar = (AsyncResult)msg.obj; |
| if (ar.exception == null) { |
| ints = (int[]) ar.result; |
| int otaStatus = ints[0]; |
| if (otaStatus == Phone.CDMA_OTA_PROVISION_STATUS_COMMITTED |
| || otaStatus == Phone.CDMA_OTA_PROVISION_STATUS_OTAPA_STOPPED) { |
| if (DBG) log("EVENT_OTA_PROVISION_STATUS_CHANGE: Complete, Reload MDN"); |
| mCi.getCDMASubscription( obtainMessage(EVENT_POLL_STATE_CDMA_SUBSCRIPTION)); |
| } |
| } |
| break; |
| |
| case EVENT_CDMA_PRL_VERSION_CHANGED: |
| ar = (AsyncResult)msg.obj; |
| if (ar.exception == null) { |
| ints = (int[]) ar.result; |
| mPrlVersion = Integer.toString(ints[0]); |
| } |
| break; |
| |
| case EVENT_CHANGE_IMS_STATE: |
| if (DBG) log("EVENT_CHANGE_IMS_STATE"); |
| setPowerStateToDesired(); |
| break; |
| |
| case EVENT_POLL_STATE_NETWORK_SELECTION_MODE: |
| if (DBG) log("EVENT_POLL_STATE_NETWORK_SELECTION_MODE"); |
| ar = (AsyncResult) msg.obj; |
| if (ar.exception == null && ar.result != null) { |
| ints = (int[])ar.result; |
| if (ints[0] == 1) { // Manual selection. |
| mPhone.setNetworkSelectionModeAutomatic(null); |
| } |
| } else { |
| log("Unable to getNetworkSelectionMode"); |
| } |
| break; |
| |
| default: |
| super.handleMessage(msg); |
| break; |
| } |
| } |
| |
| private void handleCdmaSubscriptionSource(int newSubscriptionSource) { |
| log("Subscription Source : " + newSubscriptionSource); |
| mIsSubscriptionFromRuim = |
| (newSubscriptionSource == CdmaSubscriptionSourceManager.SUBSCRIPTION_FROM_RUIM); |
| log("isFromRuim: " + mIsSubscriptionFromRuim); |
| saveCdmaSubscriptionSource(newSubscriptionSource); |
| if (!mIsSubscriptionFromRuim) { |
| // NV is ready when subscription source is NV |
| sendMessage(obtainMessage(EVENT_NV_READY)); |
| } |
| } |
| |
| @Override |
| protected void setPowerStateToDesired() { |
| // If we want it on and it's off, turn it on |
| if (mDesiredPowerState |
| && mCi.getRadioState() == CommandsInterface.RadioState.RADIO_OFF) { |
| mCi.setRadioPower(true, null); |
| } else if (!mDesiredPowerState && mCi.getRadioState().isOn()) { |
| DcTrackerBase dcTracker = mPhone.mDcTracker; |
| |
| // If it's on and available and we want it off gracefully |
| powerOffRadioSafely(dcTracker); |
| } else if (mDeviceShuttingDown && mCi.getRadioState().isAvailable()) { |
| mCi.requestShutdown(null); |
| } |
| } |
| |
| @Override |
| protected void updateSpnDisplay() { |
| // mOperatorAlphaLong contains the ERI text |
| String plmn = mSS.getOperatorAlphaLong(); |
| |
| if (!TextUtils.equals(plmn, mCurPlmn)) { |
| // Allow A blank plmn, "" to set showPlmn to true. Previously, we |
| // would set showPlmn to true only if plmn was not empty, i.e. was not |
| // null and not blank. But this would cause us to incorrectly display |
| // "No Service". Now showPlmn is set to true for any non null string. |
| boolean showPlmn = plmn != null; |
| if (DBG) { |
| log(String.format("updateSpnDisplay: changed sending intent" + |
| " showPlmn='%b' plmn='%s'", showPlmn, plmn)); |
| } |
| Intent intent = new Intent(TelephonyIntents.SPN_STRINGS_UPDATED_ACTION); |
| intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING); |
| intent.putExtra(TelephonyIntents.EXTRA_SHOW_SPN, false); |
| intent.putExtra(TelephonyIntents.EXTRA_SPN, ""); |
| intent.putExtra(TelephonyIntents.EXTRA_SHOW_PLMN, showPlmn); |
| intent.putExtra(TelephonyIntents.EXTRA_PLMN, plmn); |
| SubscriptionManager.putPhoneIdAndSubIdExtra(intent, mPhone.getPhoneId()); |
| mPhone.getContext().sendStickyBroadcastAsUser(intent, UserHandle.ALL); |
| } |
| |
| mCurPlmn = plmn; |
| } |
| |
| @Override |
| protected Phone getPhone() { |
| return mPhone; |
| } |
| |
| /** |
| * Hanlde the PollStateResult message |
| */ |
| protected void handlePollStateResultMessage(int what, AsyncResult ar){ |
| int ints[]; |
| String states[]; |
| switch (what) { |
| case EVENT_POLL_STATE_GPRS: { |
| states = (String[])ar.result; |
| if (DBG) { |
| log("handlePollStateResultMessage: EVENT_POLL_STATE_GPRS states.length=" + |
| states.length + " states=" + states); |
| } |
| |
| int regState = ServiceState.RIL_REG_STATE_UNKNOWN; |
| int dataRadioTechnology = 0; |
| |
| if (states.length > 0) { |
| try { |
| regState = Integer.parseInt(states[0]); |
| |
| // states[3] (if present) is the current radio technology |
| if (states.length >= 4 && states[3] != null) { |
| dataRadioTechnology = Integer.parseInt(states[3]); |
| } |
| } catch (NumberFormatException ex) { |
| loge("handlePollStateResultMessage: error parsing GprsRegistrationState: " |
| + ex); |
| } |
| } |
| |
| int dataRegState = regCodeToServiceState(regState); |
| mNewSS.setDataRegState(dataRegState); |
| mNewSS.setRilDataRadioTechnology(dataRadioTechnology); |
| if (DBG) { |
| log("handlPollStateResultMessage: cdma setDataRegState=" + dataRegState |
| + " regState=" + regState |
| + " dataRadioTechnology=" + dataRadioTechnology); |
| } |
| break; |
| } |
| |
| case EVENT_POLL_STATE_REGISTRATION_CDMA: // Handle RIL_REQUEST_REGISTRATION_STATE. |
| states = (String[])ar.result; |
| |
| int registrationState = 4; //[0] registrationState |
| int radioTechnology = -1; //[3] radioTechnology |
| int baseStationId = -1; //[4] baseStationId |
| //[5] baseStationLatitude |
| int baseStationLatitude = CdmaCellLocation.INVALID_LAT_LONG; |
| //[6] baseStationLongitude |
| int baseStationLongitude = CdmaCellLocation.INVALID_LAT_LONG; |
| int cssIndicator = 0; //[7] init with 0, because it is treated as a boolean |
| int systemId = 0; //[8] systemId |
| int networkId = 0; //[9] networkId |
| int roamingIndicator = -1; //[10] Roaming indicator |
| int systemIsInPrl = 0; //[11] Indicates if current system is in PRL |
| int defaultRoamingIndicator = 0; //[12] Is default roaming indicator from PRL |
| int reasonForDenial = 0; //[13] Denial reason if registrationState = 3 |
| |
| if (states.length >= 14) { |
| try { |
| if (states[0] != null) { |
| registrationState = Integer.parseInt(states[0]); |
| } |
| if (states[3] != null) { |
| radioTechnology = Integer.parseInt(states[3]); |
| } |
| if (states[4] != null) { |
| baseStationId = Integer.parseInt(states[4]); |
| } |
| if (states[5] != null) { |
| baseStationLatitude = Integer.parseInt(states[5]); |
| } |
| if (states[6] != null) { |
| baseStationLongitude = Integer.parseInt(states[6]); |
| } |
| // Some carriers only return lat-lngs of 0,0 |
| if (baseStationLatitude == 0 && baseStationLongitude == 0) { |
| baseStationLatitude = CdmaCellLocation.INVALID_LAT_LONG; |
| baseStationLongitude = CdmaCellLocation.INVALID_LAT_LONG; |
| } |
| if (states[7] != null) { |
| cssIndicator = Integer.parseInt(states[7]); |
| } |
| if (states[8] != null) { |
| systemId = Integer.parseInt(states[8]); |
| } |
| if (states[9] != null) { |
| networkId = Integer.parseInt(states[9]); |
| } |
| if (states[10] != null) { |
| roamingIndicator = Integer.parseInt(states[10]); |
| } |
| if (states[11] != null) { |
| systemIsInPrl = Integer.parseInt(states[11]); |
| } |
| if (states[12] != null) { |
| defaultRoamingIndicator = Integer.parseInt(states[12]); |
| } |
| if (states[13] != null) { |
| reasonForDenial = Integer.parseInt(states[13]); |
| } |
| } catch (NumberFormatException ex) { |
| loge("EVENT_POLL_STATE_REGISTRATION_CDMA: error parsing: " + ex); |
| } |
| } else { |
| throw new RuntimeException("Warning! Wrong number of parameters returned from " |
| + "RIL_REQUEST_REGISTRATION_STATE: expected 14 or more " |
| + "strings and got " + states.length + " strings"); |
| } |
| |
| mRegistrationState = registrationState; |
| // When registration state is roaming and TSB58 |
| // roaming indicator is not in the carrier-specified |
| // list of ERIs for home system, mCdmaRoaming is true. |
| mCdmaRoaming = |
| regCodeIsRoaming(registrationState) && !isRoamIndForHomeSystem(states[10]); |
| mNewSS.setState (regCodeToServiceState(registrationState)); |
| |
| mNewSS.setRilVoiceRadioTechnology(radioTechnology); |
| |
| mNewSS.setCssIndicator(cssIndicator); |
| mNewSS.setSystemAndNetworkId(systemId, networkId); |
| mRoamingIndicator = roamingIndicator; |
| mIsInPrl = (systemIsInPrl == 0) ? false : true; |
| mDefaultRoamingIndicator = defaultRoamingIndicator; |
| |
| |
| // Values are -1 if not available. |
| mNewCellLoc.setCellLocationData(baseStationId, baseStationLatitude, |
| baseStationLongitude, systemId, networkId); |
| |
| if (reasonForDenial == 0) { |
| mRegistrationDeniedReason = ServiceStateTracker.REGISTRATION_DENIED_GEN; |
| } else if (reasonForDenial == 1) { |
| mRegistrationDeniedReason = ServiceStateTracker.REGISTRATION_DENIED_AUTH; |
| } else { |
| mRegistrationDeniedReason = ""; |
| } |
| |
| if (mRegistrationState == 3) { |
| if (DBG) log("Registration denied, " + mRegistrationDeniedReason); |
| } |
| break; |
| |
| case EVENT_POLL_STATE_OPERATOR_CDMA: // Handle RIL_REQUEST_OPERATOR |
| String opNames[] = (String[])ar.result; |
| |
| if (opNames != null && opNames.length >= 3) { |
| // TODO: Do we care about overriding in this case. |
| // If the NUMERIC field isn't valid use PROPERTY_CDMA_HOME_OPERATOR_NUMERIC |
| if ((opNames[2] == null) || (opNames[2].length() < 5) |
| || ("00000".equals(opNames[2]))) { |
| opNames[2] = SystemProperties.get( |
| CDMAPhone.PROPERTY_CDMA_HOME_OPERATOR_NUMERIC, "00000"); |
| if (DBG) { |
| log("RIL_REQUEST_OPERATOR.response[2], the numeric, " + |
| " is bad. Using SystemProperties '" + |
| CDMAPhone.PROPERTY_CDMA_HOME_OPERATOR_NUMERIC + |
| "'= " + opNames[2]); |
| } |
| } |
| |
| if (!mIsSubscriptionFromRuim) { |
| // In CDMA in case on NV, the ss.mOperatorAlphaLong is set later with the |
| // ERI text, so here it is ignored what is coming from the modem. |
| mNewSS.setOperatorName(null, opNames[1], opNames[2]); |
| } else { |
| String brandOverride = mUiccController.getUiccCard() != null ? |
| mUiccController.getUiccCard().getOperatorBrandOverride() : null; |
| if (brandOverride != null) { |
| mNewSS.setOperatorName(brandOverride, brandOverride, opNames[2]); |
| } else { |
| mNewSS.setOperatorName(opNames[0], opNames[1], opNames[2]); |
| } |
| } |
| } else { |
| if (DBG) log("EVENT_POLL_STATE_OPERATOR_CDMA: error parsing opNames"); |
| } |
| break; |
| |
| default: |
| loge("handlePollStateResultMessage: RIL response handle in wrong phone!" |
| + " Expected CDMA RIL request and get GSM RIL request."); |
| break; |
| } |
| } |
| |
| /** |
| * Handle the result of one of the pollState() - related requests |
| */ |
| @Override |
| protected void handlePollStateResult(int what, AsyncResult ar) { |
| // Ignore stale requests from last poll. |
| if (ar.userObj != mPollingContext) return; |
| |
| if (ar.exception != null) { |
| CommandException.Error err=null; |
| |
| if (ar.exception instanceof CommandException) { |
| err = ((CommandException)(ar.exception)).getCommandError(); |
| } |
| |
| if (err == CommandException.Error.RADIO_NOT_AVAILABLE) { |
| // Radio has crashed or turned off. |
| cancelPollState(); |
| return; |
| } |
| |
| if (!mCi.getRadioState().isOn()) { |
| // Radio has crashed or turned off. |
| cancelPollState(); |
| return; |
| } |
| |
| if (err != CommandException.Error.OP_NOT_ALLOWED_BEFORE_REG_NW) { |
| loge("handlePollStateResult: RIL returned an error where it must succeed" |
| + ar.exception); |
| } |
| } else try { |
| handlePollStateResultMessage(what, ar); |
| } catch (RuntimeException ex) { |
| loge("handlePollStateResult: Exception while polling service state. " |
| + "Probably malformed RIL response." + ex); |
| } |
| |
| mPollingContext[0]--; |
| |
| if (mPollingContext[0] == 0) { |
| boolean namMatch = false; |
| if (!isSidsAllZeros() && isHomeSid(mNewSS.getSystemId())) { |
| namMatch = true; |
| } |
| |
| // Setting SS Roaming (general) |
| if (mIsSubscriptionFromRuim) { |
| mNewSS.setRoaming(isRoamingBetweenOperators(mCdmaRoaming, mNewSS)); |
| } else { |
| mNewSS.setRoaming(mCdmaRoaming); |
| } |
| |
| // Setting SS CdmaRoamingIndicator and CdmaDefaultRoamingIndicator |
| mNewSS.setCdmaDefaultRoamingIndicator(mDefaultRoamingIndicator); |
| mNewSS.setCdmaRoamingIndicator(mRoamingIndicator); |
| boolean isPrlLoaded = true; |
| if (TextUtils.isEmpty(mPrlVersion)) { |
| isPrlLoaded = false; |
| } |
| if (!isPrlLoaded || (mNewSS.getRilVoiceRadioTechnology() |
| == ServiceState.RIL_RADIO_TECHNOLOGY_UNKNOWN)) { |
| log("Turn off roaming indicator if !isPrlLoaded or voice RAT is unknown"); |
| mNewSS.setCdmaRoamingIndicator(EriInfo.ROAMING_INDICATOR_OFF); |
| } else if (!isSidsAllZeros()) { |
| if (!namMatch && !mIsInPrl) { |
| // Use default |
| mNewSS.setCdmaRoamingIndicator(mDefaultRoamingIndicator); |
| } else if (namMatch && !mIsInPrl) { |
| // TODO this will be removed when we handle roaming on LTE on CDMA+LTE phones |
| if (mNewSS.getRilVoiceRadioTechnology() |
| == ServiceState.RIL_RADIO_TECHNOLOGY_LTE) { |
| log("Turn off roaming indicator as voice is LTE"); |
| mNewSS.setCdmaRoamingIndicator(EriInfo.ROAMING_INDICATOR_OFF); |
| } else { |
| mNewSS.setCdmaRoamingIndicator(EriInfo.ROAMING_INDICATOR_FLASH); |
| } |
| } else if (!namMatch && mIsInPrl) { |
| // Use the one from PRL/ERI |
| mNewSS.setCdmaRoamingIndicator(mRoamingIndicator); |
| } else { |
| // It means namMatch && mIsInPrl |
| if ((mRoamingIndicator <= 2)) { |
| mNewSS.setCdmaRoamingIndicator(EriInfo.ROAMING_INDICATOR_OFF); |
| } else { |
| // Use the one from PRL/ERI |
| mNewSS.setCdmaRoamingIndicator(mRoamingIndicator); |
| } |
| } |
| } |
| |
| int roamingIndicator = mNewSS.getCdmaRoamingIndicator(); |
| mNewSS.setCdmaEriIconIndex(mPhone.mEriManager.getCdmaEriIconIndex(roamingIndicator, |
| mDefaultRoamingIndicator)); |
| mNewSS.setCdmaEriIconMode(mPhone.mEriManager.getCdmaEriIconMode(roamingIndicator, |
| mDefaultRoamingIndicator)); |
| |
| // NOTE: Some operator may require overriding mCdmaRoaming |
| // (set by the modem), depending on the mRoamingIndicator. |
| |
| if (DBG) { |
| log("Set CDMA Roaming Indicator to: " + mNewSS.getCdmaRoamingIndicator() |
| + ". mCdmaRoaming = " + mCdmaRoaming + ", isPrlLoaded = " + isPrlLoaded |
| + ". namMatch = " + namMatch + " , mIsInPrl = " + mIsInPrl |
| + ", mRoamingIndicator = " + mRoamingIndicator |
| + ", mDefaultRoamingIndicator= " + mDefaultRoamingIndicator); |
| } |
| pollStateDone(); |
| } |
| |
| } |
| |
| protected void setSignalStrengthDefaultValues() { |
| mSignalStrength = new SignalStrength( false); |
| } |
| |
| /** |
| * A complete "service state" from our perspective is |
| * composed of a handful of separate requests to the radio. |
| * |
| * We make all of these requests at once, but then abandon them |
| * and start over again if the radio notifies us that some |
| * event has changed |
| */ |
| @Override |
| public void pollState() { |
| mPollingContext = new int[1]; |
| mPollingContext[0] = 0; |
| |
| switch (mCi.getRadioState()) { |
| case RADIO_UNAVAILABLE: |
| mNewSS.setStateOutOfService(); |
| mNewCellLoc.setStateInvalid(); |
| setSignalStrengthDefaultValues(); |
| mGotCountryCode = false; |
| |
| pollStateDone(); |
| break; |
| |
| case RADIO_OFF: |
| mNewSS.setStateOff(); |
| mNewCellLoc.setStateInvalid(); |
| setSignalStrengthDefaultValues(); |
| mGotCountryCode = false; |
| |
| pollStateDone(); |
| break; |
| |
| default: |
| // Issue all poll-related commands at once, then count |
| // down the responses which are allowed to arrive |
| // out-of-order. |
| |
| mPollingContext[0]++; |
| // RIL_REQUEST_OPERATOR is necessary for CDMA |
| mCi.getOperator( |
| obtainMessage(EVENT_POLL_STATE_OPERATOR_CDMA, mPollingContext)); |
| |
| mPollingContext[0]++; |
| // RIL_REQUEST_VOICE_REGISTRATION_STATE is necessary for CDMA |
| mCi.getVoiceRegistrationState( |
| obtainMessage(EVENT_POLL_STATE_REGISTRATION_CDMA, mPollingContext)); |
| |
| mPollingContext[0]++; |
| // RIL_REQUEST_DATA_REGISTRATION_STATE |
| mCi.getDataRegistrationState(obtainMessage(EVENT_POLL_STATE_GPRS, |
| mPollingContext)); |
| break; |
| } |
| } |
| |
| protected void fixTimeZone(String isoCountryCode) { |
| TimeZone zone = null; |
| // If the offset is (0, false) and the time zone property |
| // is set, use the time zone property rather than GMT. |
| String zoneName = SystemProperties.get(TIMEZONE_PROPERTY); |
| if (DBG) { |
| log("fixTimeZone zoneName='" + zoneName + |
| "' mZoneOffset=" + mZoneOffset + " mZoneDst=" + mZoneDst + |
| " iso-cc='" + isoCountryCode + |
| "' iso-cc-idx=" + Arrays.binarySearch(GMT_COUNTRY_CODES, isoCountryCode)); |
| } |
| if ((mZoneOffset == 0) && (mZoneDst == false) && (zoneName != null) |
| && (zoneName.length() > 0) |
| && (Arrays.binarySearch(GMT_COUNTRY_CODES, isoCountryCode) < 0)) { |
| // For NITZ string without time zone, |
| // need adjust time to reflect default time zone setting |
| zone = TimeZone.getDefault(); |
| if (mNeedFixZone) { |
| long ctm = System.currentTimeMillis(); |
| long tzOffset = zone.getOffset(ctm); |
| if (DBG) { |
| log("fixTimeZone: tzOffset=" + tzOffset + |
| " ltod=" + TimeUtils.logTimeOfDay(ctm)); |
| } |
| if (getAutoTime()) { |
| long adj = ctm - tzOffset; |
| if (DBG) log("fixTimeZone: adj ltod=" + TimeUtils.logTimeOfDay(adj)); |
| setAndBroadcastNetworkSetTime(adj); |
| } else { |
| // Adjust the saved NITZ time to account for tzOffset. |
| mSavedTime = mSavedTime - tzOffset; |
| if (DBG) log("fixTimeZone: adj mSavedTime=" + mSavedTime); |
| } |
| } |
| if (DBG) log("fixTimeZone: using default TimeZone"); |
| } else if (isoCountryCode.equals("")) { |
| // Country code not found. This is likely a test network. |
| // Get a TimeZone based only on the NITZ parameters (best guess). |
| zone = getNitzTimeZone(mZoneOffset, mZoneDst, mZoneTime); |
| if (DBG) log("fixTimeZone: using NITZ TimeZone"); |
| } else { |
| zone = TimeUtils.getTimeZone(mZoneOffset, mZoneDst, mZoneTime, isoCountryCode); |
| if (DBG) log("fixTimeZone: using getTimeZone(off, dst, time, iso)"); |
| } |
| |
| mNeedFixZone = false; |
| |
| if (zone != null) { |
| log("fixTimeZone: zone != null zone.getID=" + zone.getID()); |
| if (getAutoTimeZone()) { |
| setAndBroadcastNetworkSetTimeZone(zone.getID()); |
| } else { |
| log("fixTimeZone: skip changing zone as getAutoTimeZone was false"); |
| } |
| saveNitzTimeZone(zone.getID()); |
| } else { |
| log("fixTimeZone: zone == null, do nothing for zone"); |
| } |
| } |
| |
| protected void pollStateDone() { |
| if (DBG) log("pollStateDone: cdma oldSS=[" + mSS + "] newSS=[" + mNewSS + "]"); |
| |
| if (Build.IS_DEBUGGABLE && SystemProperties.getBoolean(PROP_FORCE_ROAMING, false)) { |
| mNewSS.setRoaming(true); |
| } |
| |
| useDataRegStateForDataOnlyDevices(); |
| |
| boolean hasRegistered = |
| mSS.getVoiceRegState() != ServiceState.STATE_IN_SERVICE |
| && mNewSS.getVoiceRegState() == ServiceState.STATE_IN_SERVICE; |
| |
| boolean hasDeregistered = |
| mSS.getVoiceRegState() == ServiceState.STATE_IN_SERVICE |
| && mNewSS.getVoiceRegState() != ServiceState.STATE_IN_SERVICE; |
| |
| boolean hasCdmaDataConnectionAttached = |
| mSS.getDataRegState() != ServiceState.STATE_IN_SERVICE |
| && mNewSS.getDataRegState() == ServiceState.STATE_IN_SERVICE; |
| |
| boolean hasCdmaDataConnectionDetached = |
| mSS.getDataRegState() == ServiceState.STATE_IN_SERVICE |
| && mNewSS.getDataRegState() != ServiceState.STATE_IN_SERVICE; |
| |
| boolean hasCdmaDataConnectionChanged = |
| mSS.getDataRegState() != mNewSS.getDataRegState(); |
| |
| boolean hasRilVoiceRadioTechnologyChanged = |
| mSS.getRilVoiceRadioTechnology() != mNewSS.getRilVoiceRadioTechnology(); |
| |
| boolean hasRilDataRadioTechnologyChanged = |
| mSS.getRilDataRadioTechnology() != mNewSS.getRilDataRadioTechnology(); |
| |
| boolean hasChanged = !mNewSS.equals(mSS); |
| |
| boolean hasRoamingOn = !mSS.getRoaming() && mNewSS.getRoaming(); |
| |
| boolean hasRoamingOff = mSS.getRoaming() && !mNewSS.getRoaming(); |
| |
| boolean hasLocationChanged = !mNewCellLoc.equals(mCellLoc); |
| |
| // Add an event log when connection state changes |
| if (mSS.getVoiceRegState() != mNewSS.getVoiceRegState() || |
| mSS.getDataRegState() != mNewSS.getDataRegState()) { |
| EventLog.writeEvent(EventLogTags.CDMA_SERVICE_STATE_CHANGE, |
| mSS.getVoiceRegState(), mSS.getDataRegState(), |
| mNewSS.getVoiceRegState(), mNewSS.getDataRegState()); |
| } |
| |
| ServiceState tss; |
| tss = mSS; |
| mSS = mNewSS; |
| mNewSS = tss; |
| // clean slate for next time |
| mNewSS.setStateOutOfService(); |
| |
| CdmaCellLocation tcl = mCellLoc; |
| mCellLoc = mNewCellLoc; |
| mNewCellLoc = tcl; |
| |
| if (hasRilVoiceRadioTechnologyChanged) { |
| updatePhoneObject(); |
| } |
| |
| if (hasRilDataRadioTechnologyChanged) { |
| mPhone.setSystemProperty(TelephonyProperties.PROPERTY_DATA_NETWORK_TYPE, |
| ServiceState.rilRadioTechnologyToString(mSS.getRilDataRadioTechnology())); |
| } |
| |
| if (hasRegistered) { |
| mNetworkAttachedRegistrants.notifyRegistrants(); |
| } |
| |
| if (hasChanged) { |
| if ((mCi.getRadioState().isOn()) && (!mIsSubscriptionFromRuim)) { |
| String eriText; |
| // Now the CDMAPhone sees the new ServiceState so it can get the new ERI text |
| if (mSS.getVoiceRegState() == ServiceState.STATE_IN_SERVICE) { |
| eriText = mPhone.getCdmaEriText(); |
| } else { |
| // Note that ServiceState.STATE_OUT_OF_SERVICE is valid used for |
| // mRegistrationState 0,2,3 and 4 |
| eriText = mPhone.getContext().getText( |
| com.android.internal.R.string.roamingTextSearching).toString(); |
| } |
| mSS.setOperatorAlphaLong(eriText); |
| } |
| |
| String operatorNumeric; |
| |
| mPhone.setSystemProperty(TelephonyProperties.PROPERTY_OPERATOR_ALPHA, |
| mSS.getOperatorAlphaLong()); |
| |
| String prevOperatorNumeric = |
| SystemProperties.get(TelephonyProperties.PROPERTY_OPERATOR_NUMERIC, ""); |
| operatorNumeric = mSS.getOperatorNumeric(); |
| |
| // try to fix the invalid Operator Numeric |
| if (isInvalidOperatorNumeric(operatorNumeric)) { |
| int sid = mSS.getSystemId(); |
| operatorNumeric = fixUnknownMcc(operatorNumeric, sid); |
| } |
| |
| mPhone.setSystemProperty(TelephonyProperties.PROPERTY_OPERATOR_NUMERIC, operatorNumeric); |
| updateCarrierMccMncConfiguration(operatorNumeric, |
| prevOperatorNumeric, mPhone.getContext()); |
| |
| if (isInvalidOperatorNumeric(operatorNumeric)) { |
| if (DBG) log("operatorNumeric "+ operatorNumeric +"is invalid"); |
| mPhone.setSystemProperty(TelephonyProperties.PROPERTY_OPERATOR_ISO_COUNTRY, ""); |
| mGotCountryCode = false; |
| } else { |
| String isoCountryCode = ""; |
| String mcc = operatorNumeric.substring(0, 3); |
| try{ |
| isoCountryCode = MccTable.countryCodeForMcc(Integer.parseInt( |
| operatorNumeric.substring(0,3))); |
| } catch ( NumberFormatException ex){ |
| loge("pollStateDone: countryCodeForMcc error" + ex); |
| } catch ( StringIndexOutOfBoundsException ex) { |
| loge("pollStateDone: countryCodeForMcc error" + ex); |
| } |
| |
| mPhone.setSystemProperty(TelephonyProperties.PROPERTY_OPERATOR_ISO_COUNTRY, |
| isoCountryCode); |
| mGotCountryCode = true; |
| |
| setOperatorIdd(operatorNumeric); |
| |
| if (shouldFixTimeZoneNow(mPhone, operatorNumeric, prevOperatorNumeric, |
| mNeedFixZone)) { |
| fixTimeZone(isoCountryCode); |
| } |
| } |
| |
| mPhone.setSystemProperty(TelephonyProperties.PROPERTY_OPERATOR_ISROAMING, |
| mSS.getRoaming() ? "true" : "false"); |
| |
| updateSpnDisplay(); |
| mPhone.notifyServiceStateChanged(mSS); |
| } |
| |
| if (hasCdmaDataConnectionAttached) { |
| mAttachedRegistrants.notifyRegistrants(); |
| } |
| |
| if (hasCdmaDataConnectionDetached) { |
| mDetachedRegistrants.notifyRegistrants(); |
| } |
| |
| if (hasCdmaDataConnectionChanged || hasRilDataRadioTechnologyChanged) { |
| notifyDataRegStateRilRadioTechnologyChanged(); |
| mPhone.notifyDataConnection(null); |
| } |
| |
| if (hasRoamingOn) { |
| mRoamingOnRegistrants.notifyRegistrants(); |
| } |
| |
| if (hasRoamingOff) { |
| mRoamingOffRegistrants.notifyRegistrants(); |
| } |
| |
| if (hasLocationChanged) { |
| mPhone.notifyLocationChanged(); |
| } |
| // TODO: Add CdmaCellIdenity updating, see CdmaLteServiceStateTracker. |
| } |
| |
| protected boolean isInvalidOperatorNumeric(String operatorNumeric) { |
| return operatorNumeric == null || operatorNumeric.length() < 5 || |
| operatorNumeric.startsWith(INVALID_MCC); |
| } |
| |
| protected String fixUnknownMcc(String operatorNumeric, int sid) { |
| if (sid <= 0) { |
| // no cdma information is available, do nothing |
| return operatorNumeric; |
| } |
| |
| // resolve the mcc from sid; |
| // if mSavedTimeZone is null, TimeZone would get the default timeZone, |
| // and the fixTimeZone couldn't help, because it depends on operator Numeric; |
| // if the sid is conflict and timezone is unavailable, the mcc may be not right. |
| boolean isNitzTimeZone = false; |
| int timeZone = 0; |
| TimeZone tzone = null; |
| if (mSavedTimeZone != null) { |
| timeZone = |
| TimeZone.getTimeZone(mSavedTimeZone).getRawOffset()/MS_PER_HOUR; |
| isNitzTimeZone = true; |
| } else { |
| tzone = getNitzTimeZone(mZoneOffset, mZoneDst, mZoneTime); |
| if (tzone != null) |
| timeZone = tzone.getRawOffset()/MS_PER_HOUR; |
| } |
| |
| int mcc = mHbpcdUtils.getMcc(sid, |
| timeZone, (mZoneDst ? 1 : 0), isNitzTimeZone); |
| if (mcc > 0) { |
| operatorNumeric = Integer.toString(mcc) + DEFAULT_MNC; |
| } |
| return operatorNumeric; |
| } |
| |
| protected void setOperatorIdd(String operatorNumeric) { |
| // Retrieve the current country information |
| // with the MCC got from opeatorNumeric. |
| String idd = mHbpcdUtils.getIddByMcc( |
| Integer.parseInt(operatorNumeric.substring(0,3))); |
| if (idd != null && !idd.isEmpty()) { |
| mPhone.setSystemProperty(TelephonyProperties.PROPERTY_OPERATOR_IDP_STRING, |
| idd); |
| } else { |
| // use default "+", since we don't know the current IDP |
| mPhone.setSystemProperty(TelephonyProperties.PROPERTY_OPERATOR_IDP_STRING, "+"); |
| } |
| } |
| |
| /** |
| * Returns a TimeZone object based only on parameters from the NITZ string. |
| */ |
| private TimeZone getNitzTimeZone(int offset, boolean dst, long when) { |
| TimeZone guess = findTimeZone(offset, dst, when); |
| if (guess == null) { |
| // Couldn't find a proper timezone. Perhaps the DST data is wrong. |
| guess = findTimeZone(offset, !dst, when); |
| } |
| if (DBG) log("getNitzTimeZone returning " + (guess == null ? guess : guess.getID())); |
| return guess; |
| } |
| |
| private TimeZone findTimeZone(int offset, boolean dst, long when) { |
| int rawOffset = offset; |
| if (dst) { |
| rawOffset -= MS_PER_HOUR; |
| } |
| String[] zones = TimeZone.getAvailableIDs(rawOffset); |
| TimeZone guess = null; |
| Date d = new Date(when); |
| for (String zone : zones) { |
| TimeZone tz = TimeZone.getTimeZone(zone); |
| if (tz.getOffset(when) == offset && |
| tz.inDaylightTime(d) == dst) { |
| guess = tz; |
| break; |
| } |
| } |
| |
| return guess; |
| } |
| |
| /** |
| * TODO: This code is exactly the same as in GsmServiceStateTracker |
| * and has a TODO to not poll signal strength if screen is off. |
| * This code should probably be hoisted to the base class so |
| * the fix, when added, works for both. |
| */ |
| private void |
| queueNextSignalStrengthPoll() { |
| if (mDontPollSignalStrength) { |
| // The radio is telling us about signal strength changes |
| // we don't have to ask it |
| return; |
| } |
| |
| Message msg; |
| |
| msg = obtainMessage(); |
| msg.what = EVENT_POLL_SIGNAL_STRENGTH; |
| |
| // TODO Don't poll signal strength if screen is off |
| sendMessageDelayed(msg, POLL_PERIOD_MILLIS); |
| } |
| |
| protected int radioTechnologyToDataServiceState(int code) { |
| int retVal = ServiceState.STATE_OUT_OF_SERVICE; |
| switch(code) { |
| case 0: |
| case 1: |
| case 2: |
| case 3: |
| case 4: |
| case 5: |
| break; |
| case 6: // RADIO_TECHNOLOGY_1xRTT |
| case 7: // RADIO_TECHNOLOGY_EVDO_0 |
| case 8: // RADIO_TECHNOLOGY_EVDO_A |
| case 12: // RADIO_TECHNOLOGY_EVDO_B |
| case 13: // RADIO_TECHNOLOGY_EHRPD |
| retVal = ServiceState.STATE_IN_SERVICE; |
| break; |
| default: |
| loge("radioTechnologyToDataServiceState: Wrong radioTechnology code."); |
| break; |
| } |
| return(retVal); |
| } |
| |
| /** code is registration state 0-5 from TS 27.007 7.2 */ |
| protected int |
| regCodeToServiceState(int code) { |
| switch (code) { |
| case 0: // Not searching and not registered |
| return ServiceState.STATE_OUT_OF_SERVICE; |
| case 1: |
| return ServiceState.STATE_IN_SERVICE; |
| case 2: // 2 is "searching", fall through |
| case 3: // 3 is "registration denied", fall through |
| case 4: // 4 is "unknown", not valid in current baseband |
| return ServiceState.STATE_OUT_OF_SERVICE; |
| case 5:// 5 is "Registered, roaming" |
| return ServiceState.STATE_IN_SERVICE; |
| |
| default: |
| loge("regCodeToServiceState: unexpected service state " + code); |
| return ServiceState.STATE_OUT_OF_SERVICE; |
| } |
| } |
| |
| @Override |
| public int getCurrentDataConnectionState() { |
| return mSS.getDataRegState(); |
| } |
| |
| /** |
| * code is registration state 0-5 from TS 27.007 7.2 |
| * returns true if registered roam, false otherwise |
| */ |
| private boolean |
| regCodeIsRoaming (int code) { |
| // 5 is "in service -- roam" |
| return 5 == code; |
| } |
| |
| /** |
| * Determine whether a roaming indicator is in the carrier-specified list of ERIs for |
| * home system |
| * |
| * @param roamInd roaming indicator in String |
| * @return true if the roamInd is in the carrier-specified list of ERIs for home network |
| */ |
| private boolean isRoamIndForHomeSystem(String roamInd) { |
| // retrieve the carrier-specified list of ERIs for home system |
| String[] homeRoamIndicators = mPhone.getContext().getResources() |
| .getStringArray(com.android.internal.R.array.config_cdma_home_system); |
| |
| if (homeRoamIndicators != null) { |
| // searches through the comma-separated list for a match, |
| // return true if one is found. |
| for (String homeRoamInd : homeRoamIndicators) { |
| if (homeRoamInd.equals(roamInd)) { |
| return true; |
| } |
| } |
| // no matches found against the list! |
| return false; |
| } |
| |
| // no system property found for the roaming indicators for home system |
| return false; |
| } |
| |
| /** |
| * Set roaming state when cdmaRoaming is true and ons is different from spn |
| * @param cdmaRoaming TS 27.007 7.2 CREG registered roaming |
| * @param s ServiceState hold current ons |
| * @return true for roaming state set |
| */ |
| private |
| boolean isRoamingBetweenOperators(boolean cdmaRoaming, ServiceState s) { |
| String spn = getSystemProperty(TelephonyProperties.PROPERTY_ICC_OPERATOR_ALPHA, "empty"); |
| |
| // NOTE: in case of RUIM we should completely ignore the ERI data file and |
| // mOperatorAlphaLong is set from RIL_REQUEST_OPERATOR response 0 (alpha ONS) |
| String onsl = s.getOperatorAlphaLong(); |
| String onss = s.getOperatorAlphaShort(); |
| |
| boolean equalsOnsl = onsl != null && spn.equals(onsl); |
| boolean equalsOnss = onss != null && spn.equals(onss); |
| |
| return cdmaRoaming && !(equalsOnsl || equalsOnss); |
| } |
| |
| |
| /** |
| * nitzReceiveTime is time_t that the NITZ time was posted |
| */ |
| |
| private |
| void setTimeFromNITZString (String nitz, long nitzReceiveTime) |
| { |
| // "yy/mm/dd,hh:mm:ss(+/-)tz" |
| // tz is in number of quarter-hours |
| |
| long start = SystemClock.elapsedRealtime(); |
| if (DBG) { |
| log("NITZ: " + nitz + "," + nitzReceiveTime + |
| " start=" + start + " delay=" + (start - nitzReceiveTime)); |
| } |
| |
| try { |
| /* NITZ time (hour:min:sec) will be in UTC but it supplies the timezone |
| * offset as well (which we won't worry about until later) */ |
| Calendar c = Calendar.getInstance(TimeZone.getTimeZone("GMT")); |
| |
| c.clear(); |
| c.set(Calendar.DST_OFFSET, 0); |
| |
| String[] nitzSubs = nitz.split("[/:,+-]"); |
| |
| int year = 2000 + Integer.parseInt(nitzSubs[0]); |
| c.set(Calendar.YEAR, year); |
| |
| // month is 0 based! |
| int month = Integer.parseInt(nitzSubs[1]) - 1; |
| c.set(Calendar.MONTH, month); |
| |
| int date = Integer.parseInt(nitzSubs[2]); |
| c.set(Calendar.DATE, date); |
| |
| int hour = Integer.parseInt(nitzSubs[3]); |
| c.set(Calendar.HOUR, hour); |
| |
| int minute = Integer.parseInt(nitzSubs[4]); |
| c.set(Calendar.MINUTE, minute); |
| |
| int second = Integer.parseInt(nitzSubs[5]); |
| c.set(Calendar.SECOND, second); |
| |
| boolean sign = (nitz.indexOf('-') == -1); |
| |
| int tzOffset = Integer.parseInt(nitzSubs[6]); |
| |
| int dst = (nitzSubs.length >= 8 ) ? Integer.parseInt(nitzSubs[7]) |
| : 0; |
| |
| // The zone offset received from NITZ is for current local time, |
| // so DST correction is already applied. Don't add it again. |
| // |
| // tzOffset += dst * 4; |
| // |
| // We could unapply it if we wanted the raw offset. |
| |
| tzOffset = (sign ? 1 : -1) * tzOffset * 15 * 60 * 1000; |
| |
| TimeZone zone = null; |
| |
| // As a special extension, the Android emulator appends the name of |
| // the host computer's timezone to the nitz string. this is zoneinfo |
| // timezone name of the form Area!Location or Area!Location!SubLocation |
| // so we need to convert the ! into / |
| if (nitzSubs.length >= 9) { |
| String tzname = nitzSubs[8].replace('!','/'); |
| zone = TimeZone.getTimeZone( tzname ); |
| } |
| |
| String iso = getSystemProperty(TelephonyProperties.PROPERTY_OPERATOR_ISO_COUNTRY, ""); |
| |
| if (zone == null) { |
| if (mGotCountryCode) { |
| if (iso != null && iso.length() > 0) { |
| zone = TimeUtils.getTimeZone(tzOffset, dst != 0, |
| c.getTimeInMillis(), |
| iso); |
| } else { |
| // We don't have a valid iso country code. This is |
| // most likely because we're on a test network that's |
| // using a bogus MCC (eg, "001"), so get a TimeZone |
| // based only on the NITZ parameters. |
| zone = getNitzTimeZone(tzOffset, (dst != 0), c.getTimeInMillis()); |
| } |
| } |
| } |
| |
| if ((zone == null) || (mZoneOffset != tzOffset) || (mZoneDst != (dst != 0))){ |
| // We got the time before the country or the zone has changed |
| // so we don't know how to identify the DST rules yet. Save |
| // the information and hope to fix it up later. |
| |
| mNeedFixZone = true; |
| mZoneOffset = tzOffset; |
| mZoneDst = dst != 0; |
| mZoneTime = c.getTimeInMillis(); |
| } |
| if (DBG) { |
| log("NITZ: tzOffset=" + tzOffset + " dst=" + dst + " zone=" + |
| (zone!=null ? zone.getID() : "NULL") + |
| " iso=" + iso + " mGotCountryCode=" + mGotCountryCode + |
| " mNeedFixZone=" + mNeedFixZone); |
| } |
| |
| if (zone != null) { |
| if (getAutoTimeZone()) { |
| setAndBroadcastNetworkSetTimeZone(zone.getID()); |
| } |
| saveNitzTimeZone(zone.getID()); |
| } |
| |
| String ignore = SystemProperties.get("gsm.ignore-nitz"); |
| if (ignore != null && ignore.equals("yes")) { |
| if (DBG) log("NITZ: Not setting clock because gsm.ignore-nitz is set"); |
| return; |
| } |
| |
| try { |
| mWakeLock.acquire(); |
| |
| /** |
| * Correct the NITZ time by how long its taken to get here. |
| */ |
| long millisSinceNitzReceived |
| = SystemClock.elapsedRealtime() - nitzReceiveTime; |
| |
| if (millisSinceNitzReceived < 0) { |
| // Sanity check: something is wrong |
| if (DBG) { |
| log("NITZ: not setting time, clock has rolled " |
| + "backwards since NITZ time was received, " |
| + nitz); |
| } |
| return; |
| } |
| |
| if (millisSinceNitzReceived > Integer.MAX_VALUE) { |
| // If the time is this far off, something is wrong > 24 days! |
| if (DBG) { |
| log("NITZ: not setting time, processing has taken " |
| + (millisSinceNitzReceived / (1000 * 60 * 60 * 24)) |
| + " days"); |
| } |
| return; |
| } |
| |
| // Note: with range checks above, cast to int is safe |
| c.add(Calendar.MILLISECOND, (int)millisSinceNitzReceived); |
| |
| if (getAutoTime()) { |
| /** |
| * Update system time automatically |
| */ |
| long gained = c.getTimeInMillis() - System.currentTimeMillis(); |
| long timeSinceLastUpdate = SystemClock.elapsedRealtime() - mSavedAtTime; |
| int nitzUpdateSpacing = Settings.Global.getInt(mCr, |
| Settings.Global.NITZ_UPDATE_SPACING, mNitzUpdateSpacing); |
| int nitzUpdateDiff = Settings.Global.getInt(mCr, |
| Settings.Global.NITZ_UPDATE_DIFF, mNitzUpdateDiff); |
| |
| if ((mSavedAtTime == 0) || (timeSinceLastUpdate > nitzUpdateSpacing) |
| || (Math.abs(gained) > nitzUpdateDiff)) { |
| if (DBG) { |
| log("NITZ: Auto updating time of day to " + c.getTime() |
| + " NITZ receive delay=" + millisSinceNitzReceived |
| + "ms gained=" + gained + "ms from " + nitz); |
| } |
| |
| setAndBroadcastNetworkSetTime(c.getTimeInMillis()); |
| } else { |
| if (DBG) { |
| log("NITZ: ignore, a previous update was " |
| + timeSinceLastUpdate + "ms ago and gained=" + gained + "ms"); |
| } |
| return; |
| } |
| } |
| |
| /** |
| * Update properties and save the time we did the update |
| */ |
| if (DBG) log("NITZ: update nitz time property"); |
| SystemProperties.set("gsm.nitz.time", String.valueOf(c.getTimeInMillis())); |
| mSavedTime = c.getTimeInMillis(); |
| mSavedAtTime = SystemClock.elapsedRealtime(); |
| } finally { |
| long end = SystemClock.elapsedRealtime(); |
| if (DBG) log("NITZ: end=" + end + " dur=" + (end - start)); |
| mWakeLock.release(); |
| } |
| } catch (RuntimeException ex) { |
| loge("NITZ: Parsing NITZ time " + nitz + " ex=" + ex); |
| } |
| } |
| |
| private boolean getAutoTime() { |
| try { |
| return Settings.Global.getInt(mCr, Settings.Global.AUTO_TIME) > 0; |
| } catch (SettingNotFoundException snfe) { |
| return true; |
| } |
| } |
| |
| private boolean getAutoTimeZone() { |
| try { |
| return Settings.Global.getInt(mCr, Settings.Global.AUTO_TIME_ZONE) > 0; |
| } catch (SettingNotFoundException snfe) { |
| return true; |
| } |
| } |
| |
| private void saveNitzTimeZone(String zoneId) { |
| mSavedTimeZone = zoneId; |
| } |
| |
| /** |
| * Set the timezone and send out a sticky broadcast so the system can |
| * determine if the timezone was set by the carrier. |
| * |
| * @param zoneId timezone set by carrier |
| */ |
| private void setAndBroadcastNetworkSetTimeZone(String zoneId) { |
| if (DBG) log("setAndBroadcastNetworkSetTimeZone: setTimeZone=" + zoneId); |
| AlarmManager alarm = |
| (AlarmManager) mPhone.getContext().getSystemService(Context.ALARM_SERVICE); |
| alarm.setTimeZone(zoneId); |
| Intent intent = new Intent(TelephonyIntents.ACTION_NETWORK_SET_TIMEZONE); |
| intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING); |
| intent.putExtra("time-zone", zoneId); |
| mPhone.getContext().sendStickyBroadcastAsUser(intent, UserHandle.ALL); |
| } |
| |
| /** |
| * Set the time and Send out a sticky broadcast so the system can determine |
| * if the time was set by the carrier. |
| * |
| * @param time time set by network |
| */ |
| private void setAndBroadcastNetworkSetTime(long time) { |
| if (DBG) log("setAndBroadcastNetworkSetTime: time=" + time + "ms"); |
| SystemClock.setCurrentTimeMillis(time); |
| Intent intent = new Intent(TelephonyIntents.ACTION_NETWORK_SET_TIME); |
| intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING); |
| intent.putExtra("time", time); |
| mPhone.getContext().sendStickyBroadcastAsUser(intent, UserHandle.ALL); |
| } |
| |
| private void revertToNitzTime() { |
| if (Settings.Global.getInt(mCr, Settings.Global.AUTO_TIME, 0) == 0) { |
| return; |
| } |
| if (DBG) { |
| log("revertToNitzTime: mSavedTime=" + mSavedTime + " mSavedAtTime=" + mSavedAtTime); |
| } |
| if (mSavedTime != 0 && mSavedAtTime != 0) { |
| setAndBroadcastNetworkSetTime(mSavedTime |
| + (SystemClock.elapsedRealtime() - mSavedAtTime)); |
| } |
| } |
| |
| private void revertToNitzTimeZone() { |
| if (Settings.Global.getInt(mPhone.getContext().getContentResolver(), |
| Settings.Global.AUTO_TIME_ZONE, 0) == 0) { |
| return; |
| } |
| if (DBG) log("revertToNitzTimeZone: tz='" + mSavedTimeZone); |
| if (mSavedTimeZone != null) { |
| setAndBroadcastNetworkSetTimeZone(mSavedTimeZone); |
| } |
| } |
| |
| protected boolean isSidsAllZeros() { |
| if (mHomeSystemId != null) { |
| for (int i=0; i < mHomeSystemId.length; i++) { |
| if (mHomeSystemId[i] != 0) { |
| return false; |
| } |
| } |
| } |
| return true; |
| } |
| |
| /** |
| * Check whether a specified system ID that matches one of the home system IDs. |
| */ |
| private boolean isHomeSid(int sid) { |
| if (mHomeSystemId != null) { |
| for (int i=0; i < mHomeSystemId.length; i++) { |
| if (sid == mHomeSystemId[i]) { |
| return true; |
| } |
| } |
| } |
| return false; |
| } |
| |
| /** |
| * @return true if phone is camping on a technology |
| * that could support voice and data simultaneously. |
| */ |
| @Override |
| public boolean isConcurrentVoiceAndDataAllowed() { |
| // Note: it needs to be confirmed which CDMA network types |
| // can support voice and data calls concurrently. |
| // For the time-being, the return value will be false. |
| return false; |
| } |
| |
| public String getMdnNumber() { |
| return mMdn; |
| } |
| |
| public String getCdmaMin() { |
| return mMin; |
| } |
| |
| /** Returns null if NV is not yet ready */ |
| public String getPrlVersion() { |
| return mPrlVersion; |
| } |
| |
| /** |
| * Returns IMSI as MCC + MNC + MIN |
| */ |
| String getImsi() { |
| // TODO: When RUIM is enabled, IMSI will come from RUIM not build-time props. |
| String operatorNumeric = getSystemProperty( |
| TelephonyProperties.PROPERTY_ICC_OPERATOR_NUMERIC, ""); |
| |
| if (!TextUtils.isEmpty(operatorNumeric) && getCdmaMin() != null) { |
| return (operatorNumeric + getCdmaMin()); |
| } else { |
| return null; |
| } |
| } |
| |
| /** |
| * Check if subscription data has been assigned to mMin |
| * |
| * return true if MIN info is ready; false otherwise. |
| */ |
| public boolean isMinInfoReady() { |
| return mIsMinInfoReady; |
| } |
| |
| /** |
| * Returns OTASP_UNKNOWN, OTASP_NEEDED or OTASP_NOT_NEEDED |
| */ |
| int getOtasp() { |
| int provisioningState; |
| // for ruim, min is null means require otasp. |
| if (mIsSubscriptionFromRuim && mMin == null) { |
| return OTASP_NEEDED; |
| } |
| if (mMin == null || (mMin.length() < 6)) { |
| if (DBG) log("getOtasp: bad mMin='" + mMin + "'"); |
| provisioningState = OTASP_UNKNOWN; |
| } else { |
| if ((mMin.equals(UNACTIVATED_MIN_VALUE) |
| || mMin.substring(0,6).equals(UNACTIVATED_MIN2_VALUE)) |
| || SystemProperties.getBoolean("test_cdma_setup", false)) { |
| provisioningState = OTASP_NEEDED; |
| } else { |
| provisioningState = OTASP_NOT_NEEDED; |
| } |
| } |
| if (DBG) log("getOtasp: state=" + provisioningState); |
| return provisioningState; |
| } |
| |
| @Override |
| protected void hangupAndPowerOff() { |
| // hang up all active voice calls |
| mPhone.mCT.mRingingCall.hangupIfAlive(); |
| mPhone.mCT.mBackgroundCall.hangupIfAlive(); |
| mPhone.mCT.mForegroundCall.hangupIfAlive(); |
| mCi.setRadioPower(false, null); |
| } |
| |
| protected void parseSidNid (String sidStr, String nidStr) { |
| if (sidStr != null) { |
| String[] sid = sidStr.split(","); |
| mHomeSystemId = new int[sid.length]; |
| for (int i = 0; i < sid.length; i++) { |
| try { |
| mHomeSystemId[i] = Integer.parseInt(sid[i]); |
| } catch (NumberFormatException ex) { |
| loge("error parsing system id: " + ex); |
| } |
| } |
| } |
| if (DBG) log("CDMA_SUBSCRIPTION: SID=" + sidStr); |
| |
| if (nidStr != null) { |
| String[] nid = nidStr.split(","); |
| mHomeNetworkId = new int[nid.length]; |
| for (int i = 0; i < nid.length; i++) { |
| try { |
| mHomeNetworkId[i] = Integer.parseInt(nid[i]); |
| } catch (NumberFormatException ex) { |
| loge("CDMA_SUBSCRIPTION: error parsing network id: " + ex); |
| } |
| } |
| } |
| if (DBG) log("CDMA_SUBSCRIPTION: NID=" + nidStr); |
| } |
| |
| protected void updateOtaspState() { |
| int otaspMode = getOtasp(); |
| int oldOtaspMode = mCurrentOtaspMode; |
| mCurrentOtaspMode = otaspMode; |
| |
| // Notify apps subscription info is ready |
| if (mCdmaForSubscriptionInfoReadyRegistrants != null) { |
| if (DBG) log("CDMA_SUBSCRIPTION: call notifyRegistrants()"); |
| mCdmaForSubscriptionInfoReadyRegistrants.notifyRegistrants(); |
| } |
| if (oldOtaspMode != mCurrentOtaspMode) { |
| if (DBG) { |
| log("CDMA_SUBSCRIPTION: call notifyOtaspChanged old otaspMode=" + |
| oldOtaspMode + " new otaspMode=" + mCurrentOtaspMode); |
| } |
| mPhone.notifyOtaspChanged(mCurrentOtaspMode); |
| } |
| } |
| |
| protected UiccCardApplication getUiccCardApplication() { |
| return mUiccController.getUiccCardApplication(mPhone.getPhoneId(), |
| UiccController.APP_FAM_3GPP2); |
| } |
| |
| @Override |
| protected void onUpdateIccAvailability() { |
| if (mUiccController == null ) { |
| return; |
| } |
| |
| UiccCardApplication newUiccApplication = getUiccCardApplication(); |
| |
| if (mUiccApplcation != newUiccApplication) { |
| if (mUiccApplcation != null) { |
| log("Removing stale icc objects."); |
| mUiccApplcation.unregisterForReady(this); |
| if (mIccRecords != null) { |
| mIccRecords.unregisterForRecordsLoaded(this); |
| } |
| mIccRecords = null; |
| mUiccApplcation = null; |
| } |
| if (newUiccApplication != null) { |
| log("New card found"); |
| mUiccApplcation = newUiccApplication; |
| mIccRecords = mUiccApplcation.getIccRecords(); |
| if (mIsSubscriptionFromRuim) { |
| mUiccApplcation.registerForReady(this, EVENT_RUIM_READY, null); |
| if (mIccRecords != null) { |
| mIccRecords.registerForRecordsLoaded(this, EVENT_RUIM_RECORDS_LOADED, null); |
| } |
| } |
| } |
| } |
| } |
| |
| @Override |
| protected void log(String s) { |
| Rlog.d(LOG_TAG, "[CdmaSST] " + s); |
| } |
| |
| @Override |
| protected void loge(String s) { |
| Rlog.e(LOG_TAG, "[CdmaSST] " + s); |
| } |
| |
| @Override |
| public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { |
| pw.println("CdmaServiceStateTracker extends:"); |
| super.dump(fd, pw, args); |
| pw.flush(); |
| pw.println(" mPhone=" + mPhone); |
| pw.println(" mSS=" + mSS); |
| pw.println(" mNewSS=" + mNewSS); |
| pw.println(" mCellLoc=" + mCellLoc); |
| pw.println(" mNewCellLoc=" + mNewCellLoc); |
| pw.println(" mCurrentOtaspMode=" + mCurrentOtaspMode); |
| pw.println(" mCdmaRoaming=" + mCdmaRoaming); |
| pw.println(" mRoamingIndicator=" + mRoamingIndicator); |
| pw.println(" mIsInPrl=" + mIsInPrl); |
| pw.println(" mDefaultRoamingIndicator=" + mDefaultRoamingIndicator); |
| pw.println(" mRegistrationState=" + mRegistrationState); |
| pw.println(" mNeedFixZone=" + mNeedFixZone); |
| pw.flush(); |
| pw.println(" mZoneOffset=" + mZoneOffset); |
| pw.println(" mZoneDst=" + mZoneDst); |
| pw.println(" mZoneTime=" + mZoneTime); |
| pw.println(" mGotCountryCode=" + mGotCountryCode); |
| pw.println(" mSavedTimeZone=" + mSavedTimeZone); |
| pw.println(" mSavedTime=" + mSavedTime); |
| pw.println(" mSavedAtTime=" + mSavedAtTime); |
| pw.println(" mWakeLock=" + mWakeLock); |
| pw.println(" mCurPlmn=" + mCurPlmn); |
| pw.println(" mMdn=" + mMdn); |
| pw.println(" mHomeSystemId=" + mHomeSystemId); |
| pw.println(" mHomeNetworkId=" + mHomeNetworkId); |
| pw.println(" mMin=" + mMin); |
| pw.println(" mPrlVersion=" + mPrlVersion); |
| pw.println(" mIsMinInfoReady=" + mIsMinInfoReady); |
| pw.println(" mIsEriTextLoaded=" + mIsEriTextLoaded); |
| pw.println(" mIsSubscriptionFromRuim=" + mIsSubscriptionFromRuim); |
| pw.println(" mCdmaSSM=" + mCdmaSSM); |
| pw.println(" mRegistrationDeniedReason=" + mRegistrationDeniedReason); |
| pw.println(" mCurrentCarrier=" + mCurrentCarrier); |
| pw.flush(); |
| } |
| |
| @Override |
| public void setImsRegistrationState(boolean registered) { |
| log("ImsRegistrationState - registered : " + registered); |
| |
| if (mImsRegistrationOnOff && !registered) { |
| if (mAlarmSwitch) { |
| mImsRegistrationOnOff = registered; |
| |
| Context context = mPhone.getContext(); |
| AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); |
| am.cancel(mRadioOffIntent); |
| mAlarmSwitch = false; |
| |
| sendMessage(obtainMessage(EVENT_CHANGE_IMS_STATE)); |
| return; |
| } |
| } |
| mImsRegistrationOnOff = registered; |
| } |
| } |