blob: 21cabf6a3efe78eed70c3fe20dce490a52b406ae [file] [log] [blame]
/*
* 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);
}
}