/* * Copyright (C) 2011 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.ActivityManagerNative; import android.content.ContentValues; import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; import android.database.SQLException; import android.net.Uri; import android.os.AsyncResult; import android.os.Handler; import android.os.Message; import android.os.UserHandle; import android.preference.PreferenceManager; import android.os.PowerManager; import android.os.SystemProperties; import android.provider.Telephony; import android.text.TextUtils; import android.telephony.SubscriptionManager; import android.telephony.Rlog; import com.android.internal.telephony.CommandsInterface; import android.telephony.TelephonyManager; import com.android.internal.telephony.dataconnection.DcTracker; import com.android.internal.telephony.MccTable; import com.android.internal.telephony.OperatorInfo; import com.android.internal.telephony.PhoneConstants; import com.android.internal.telephony.PhoneNotifier; import com.android.internal.telephony.PhoneProxy; import com.android.internal.telephony.PhoneFactory; import com.android.internal.telephony.PhoneSubInfo; import com.android.internal.telephony.SMSDispatcher; import com.android.internal.telephony.SmsBroadcastUndelivered; import com.android.internal.telephony.SubscriptionController; import com.android.internal.telephony.gsm.GsmSMSDispatcher; import com.android.internal.telephony.gsm.SmsMessage; import com.android.internal.telephony.uicc.IccRecords; import com.android.internal.telephony.uicc.IsimRecords; import com.android.internal.telephony.uicc.IsimUiccRecords; import com.android.internal.telephony.uicc.RuimRecords; import com.android.internal.telephony.uicc.SIMRecords; import com.android.internal.telephony.uicc.UiccCardApplication; import com.android.internal.telephony.uicc.UiccController; import com.android.internal.telephony.ServiceStateTracker; import com.android.internal.telephony.TelephonyIntents; import com.android.internal.telephony.TelephonyProperties; import java.io.FileDescriptor; import java.io.PrintWriter; public class CDMALTEPhone extends CDMAPhone { static final String LOG_LTE_TAG = "CDMALTEPhone"; private static final boolean DBG = true; /** CdmaLtePhone in addition to RuimRecords available from * PhoneBase needs access to SIMRecords and IsimUiccRecords */ private SIMRecords mSimRecords; private IsimUiccRecords mIsimUiccRecords; // Constructors public CDMALTEPhone(Context context, CommandsInterface ci, PhoneNotifier notifier, int phoneId) { this(context, ci, notifier, false, phoneId); } public CDMALTEPhone(Context context, CommandsInterface ci, PhoneNotifier notifier, boolean unitTestMode, int phoneId) { super(context, ci, notifier, phoneId); Rlog.d(LOG_TAG, "CDMALTEPhone: constructor: sub = " + mPhoneId); mDcTracker = new DcTracker(this); } @Override protected void initSstIcc() { mSST = new CdmaLteServiceStateTracker(this); } @Override public void dispose() { synchronized(PhoneProxy.lockForRadioTechnologyChange) { if (mSimRecords != null) { mSimRecords.unregisterForRecordsLoaded(this); } super.dispose(); } } @Override public void removeReferences() { super.removeReferences(); } @Override public void handleMessage(Message msg) { AsyncResult ar; Message onComplete; // messages to be handled whether or not the phone is being destroyed // should only include messages which are being re-directed and do not use // resources of the phone being destroyed switch (msg.what) { // handle the select network completion callbacks. case EVENT_SET_NETWORK_MANUAL_COMPLETE: case EVENT_SET_NETWORK_AUTOMATIC_COMPLETE: super.handleMessage(msg); return; } if (!mIsTheCurrentActivePhone) { Rlog.e(LOG_TAG, "Received message " + msg + "[" + msg.what + "] while being destroyed. Ignoring."); return; } switch(msg.what) { case EVENT_SIM_RECORDS_LOADED: mSimRecordsLoadedRegistrants.notifyRegistrants(); break; default: super.handleMessage(msg); } } @Override public PhoneConstants.DataState getDataConnectionState(String apnType) { PhoneConstants.DataState ret = PhoneConstants.DataState.DISCONNECTED; if (mSST == null) { // Radio Technology Change is ongoing, dispose() and // removeReferences() have already been called ret = PhoneConstants.DataState.DISCONNECTED; } else if (mDcTracker.isApnTypeEnabled(apnType) == false) { ret = PhoneConstants.DataState.DISCONNECTED; } else { switch (mDcTracker.getState(apnType)) { case RETRYING: case FAILED: case IDLE: ret = PhoneConstants.DataState.DISCONNECTED; break; case CONNECTED: case DISCONNECTING: if (mCT.mState != PhoneConstants.State.IDLE && !mSST.isConcurrentVoiceAndDataAllowed()) { ret = PhoneConstants.DataState.SUSPENDED; } else { ret = PhoneConstants.DataState.CONNECTED; } break; case CONNECTING: case SCANNING: ret = PhoneConstants.DataState.CONNECTING; break; } } log("getDataConnectionState apnType=" + apnType + " ret=" + ret); return ret; } /** * Sets the "current" field in the telephony provider according to the * build-time operator numeric property * * @return true for success; false otherwise. */ @Override boolean updateCurrentCarrierInProvider(String operatorNumeric) { boolean retVal; if (mUiccController.getUiccCardApplication(mPhoneId, UiccController.APP_FAM_3GPP) == null) { if (DBG) log("updateCurrentCarrierInProvider APP_FAM_3GPP == null"); retVal = super.updateCurrentCarrierInProvider(operatorNumeric); } else { if (DBG) log("updateCurrentCarrierInProvider not updated"); retVal = true; } if (DBG) log("updateCurrentCarrierInProvider X retVal=" + retVal); return retVal; } @Override public boolean updateCurrentCarrierInProvider() { long currentDds = SubscriptionManager.getDefaultDataSubId(); String operatorNumeric = getOperatorNumeric(); Rlog.d(LOG_TAG, "updateCurrentCarrierInProvider: mSubscription = " + getSubId() + " currentDds = " + currentDds + " operatorNumeric = " + operatorNumeric); if (!TextUtils.isEmpty(operatorNumeric) && (getSubId() == currentDds)) { try { Uri uri = Uri.withAppendedPath(Telephony.Carriers.CONTENT_URI, "current"); ContentValues map = new ContentValues(); map.put(Telephony.Carriers.NUMERIC, operatorNumeric); mContext.getContentResolver().insert(uri, map); return true; } catch (SQLException e) { Rlog.e(LOG_TAG, "Can't store current operator", e); } } return false; } // return IMSI from USIM as subscriber ID. @Override public String getSubscriberId() { return (mSimRecords != null) ? mSimRecords.getIMSI() : ""; } // return GID1 from USIM @Override public String getGroupIdLevel1() { return (mSimRecords != null) ? mSimRecords.getGid1() : ""; } @Override public String getImei() { return mImei; } @Override public String getDeviceSvn() { return mImeiSv; } @Override public IsimRecords getIsimRecords() { return mIsimUiccRecords; } @Override public String getMsisdn() { return (mSimRecords != null) ? mSimRecords.getMsisdnNumber() : null; } @Override public void getAvailableNetworks(Message response) { mCi.getAvailableNetworks(response); } @Override protected void onUpdateIccAvailability() { if (mSimRecords != null) { mSimRecords.unregisterForRecordsLoaded(this); } if (mUiccController == null ) { return; } // Update IsimRecords UiccCardApplication newUiccApplication = mUiccController.getUiccCardApplication(mPhoneId, UiccController.APP_FAM_IMS); IsimUiccRecords newIsimUiccRecords = null; if (newUiccApplication != null) { newIsimUiccRecords = (IsimUiccRecords) newUiccApplication.getIccRecords(); } mIsimUiccRecords = newIsimUiccRecords; // Update UsimRecords newUiccApplication = mUiccController.getUiccCardApplication(mPhoneId, UiccController.APP_FAM_3GPP); SIMRecords newSimRecords = null; if (newUiccApplication != null) { newSimRecords = (SIMRecords) newUiccApplication.getIccRecords(); } mSimRecords = newSimRecords; if (mSimRecords != null) { mSimRecords.registerForRecordsLoaded(this, EVENT_SIM_RECORDS_LOADED, null); } super.onUpdateIccAvailability(); } @Override protected void init(Context context, PhoneNotifier notifier) { mCi.setPhoneType(PhoneConstants.PHONE_TYPE_CDMA); mCT = new CdmaCallTracker(this); mCdmaSSM = CdmaSubscriptionSourceManager.getInstance(context, mCi, this, EVENT_CDMA_SUBSCRIPTION_SOURCE_CHANGED, null); mRuimPhoneBookInterfaceManager = new RuimPhoneBookInterfaceManager(this); mSubInfo = new PhoneSubInfo(this); mEriManager = new EriManager(this, context, EriManager.ERI_FROM_XML); mCi.registerForAvailable(this, EVENT_RADIO_AVAILABLE, null); mCi.registerForOffOrNotAvailable(this, EVENT_RADIO_OFF_OR_NOT_AVAILABLE, null); mCi.registerForOn(this, EVENT_RADIO_ON, null); mCi.setOnSuppServiceNotification(this, EVENT_SSN, null); mSST.registerForNetworkAttached(this, EVENT_REGISTERED_TO_NETWORK, null); mCi.setEmergencyCallbackMode(this, EVENT_EMERGENCY_CALLBACK_MODE_ENTER, null); mCi.registerForExitEmergencyCallbackMode(this, EVENT_EXIT_EMERGENCY_CALLBACK_RESPONSE, null); PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE); mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,LOG_TAG); // This is needed to handle phone process crashes String inEcm = SystemProperties.get(TelephonyProperties.PROPERTY_INECM_MODE, "false"); mIsPhoneInEcmState = inEcm.equals("true"); if (mIsPhoneInEcmState) { // Send a message which will invoke handleExitEmergencyCallbackMode mCi.exitEmergencyCallbackMode(obtainMessage(EVENT_EXIT_EMERGENCY_CALLBACK_RESPONSE)); } // get the string that specifies the carrier OTA Sp number mCarrierOtaSpNumSchema = TelephonyManager.from(mContext).getOtaSpNumberSchemaForPhone( getPhoneId(), ""); setProperties(); } // Set the properties per subscription private void setProperties() { TelephonyManager tm = TelephonyManager.from(mContext); //Change the system property tm.setPhoneType(getPhoneId(), PhoneConstants.PHONE_TYPE_CDMA); // Sets operator alpha property by retrieving from build-time system property String operatorAlpha = SystemProperties.get("ro.cdma.home.operator.alpha"); if (!TextUtils.isEmpty(operatorAlpha)) { tm.setSimOperatorNameForPhone(getPhoneId(), operatorAlpha); } // Sets operator numeric property by retrieving from build-time system property String operatorNumeric = SystemProperties.get(PROPERTY_CDMA_HOME_OPERATOR_NUMERIC); log("update icc_operator_numeric=" + operatorNumeric); if (!TextUtils.isEmpty(operatorNumeric)) { tm.setSimOperatorNumericForPhone(getPhoneId(), operatorNumeric); SubscriptionController.getInstance().setMccMnc(operatorNumeric, getSubId()); // Sets iso country property by retrieving from build-time system property setIsoCountryProperty(operatorNumeric); // Updates MCC MNC device configuration information log("update mccmnc=" + operatorNumeric); MccTable.updateMccMncConfiguration(mContext, operatorNumeric, false); } // Sets current entry in the telephony carrier table updateCurrentCarrierInProvider(); } @Override public void setSystemProperty(String property, String value) { if(getUnitTestMode()) { return; } TelephonyManager.setTelephonyProperty(mPhoneId, property, value); } public String getSystemProperty(String property, String defValue) { if(getUnitTestMode()) { return null; } return TelephonyManager.getTelephonyProperty(mPhoneId, property, defValue); } public void updateDataConnectionTracker() { ((DcTracker)mDcTracker).update(); } public void setInternalDataEnabled(boolean enable, Message onCompleteMsg) { ((DcTracker)mDcTracker) .setInternalDataEnabled(enable, onCompleteMsg); } public boolean setInternalDataEnabledFlag(boolean enable) { return ((DcTracker)mDcTracker) .setInternalDataEnabledFlag(enable); } /** * @return operator numeric. */ public String getOperatorNumeric() { String operatorNumeric = null; IccRecords curIccRecords = null; if (mCdmaSubscriptionSource == CDMA_SUBSCRIPTION_NV) { operatorNumeric = SystemProperties.get("ro.cdma.home.operator.numeric"); } else if (mCdmaSubscriptionSource == CDMA_SUBSCRIPTION_RUIM_SIM) { curIccRecords = mSimRecords; if (curIccRecords != null) { operatorNumeric = curIccRecords.getOperatorNumeric(); } else { curIccRecords = mIccRecords.get(); if (curIccRecords != null && (curIccRecords instanceof RuimRecords)) { RuimRecords csim = (RuimRecords) curIccRecords; operatorNumeric = csim.getRUIMOperatorNumeric(); } } } if (operatorNumeric == null) { Rlog.e(LOG_TAG, "getOperatorNumeric: Cannot retrieve operatorNumeric:" + " mCdmaSubscriptionSource = " + mCdmaSubscriptionSource + " mIccRecords = " + ((curIccRecords != null) ? curIccRecords.getRecordsLoaded() : null)); } Rlog.d(LOG_TAG, "getOperatorNumeric: mCdmaSubscriptionSource = " + mCdmaSubscriptionSource + " operatorNumeric = " + operatorNumeric); return operatorNumeric; } public void registerForAllDataDisconnected(Handler h, int what, Object obj) { ((DcTracker)mDcTracker) .registerForAllDataDisconnected(h, what, obj); } public void unregisterForAllDataDisconnected(Handler h) { ((DcTracker)mDcTracker) .unregisterForAllDataDisconnected(h); } @Override public void registerForSimRecordsLoaded(Handler h, int what, Object obj) { mSimRecordsLoadedRegistrants.addUnique(h, what, obj); } @Override public void unregisterForSimRecordsLoaded(Handler h) { mSimRecordsLoadedRegistrants.remove(h); } @Override protected void log(String s) { Rlog.d(LOG_LTE_TAG, s); } protected void loge(String s) { Rlog.e(LOG_LTE_TAG, s); } protected void loge(String s, Throwable e) { Rlog.e(LOG_LTE_TAG, s, e); } @Override public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { pw.println("CDMALTEPhone extends:"); super.dump(fd, pw, args); } }