/* * 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.content.ContentValues; import android.content.Context; import android.content.SharedPreferences; import android.database.SQLException; import android.net.Uri; import android.os.AsyncResult; import android.os.Message; import android.preference.PreferenceManager; import android.provider.Telephony; import android.util.Log; import com.android.internal.telephony.CommandsInterface; import com.android.internal.telephony.OperatorInfo; import com.android.internal.telephony.Phone; import com.android.internal.telephony.PhoneConstants; import com.android.internal.telephony.PhoneNotifier; import com.android.internal.telephony.PhoneProxy; import com.android.internal.telephony.SMSDispatcher; import com.android.internal.telephony.UiccCardApplication; import com.android.internal.telephony.gsm.GsmSMSDispatcher; import com.android.internal.telephony.gsm.SIMRecords; import com.android.internal.telephony.gsm.SmsMessage; import com.android.internal.telephony.ims.IsimRecords; import com.android.internal.telephony.ims.IsimUiccRecords; import com.android.internal.telephony.uicc.UiccController; import java.io.FileDescriptor; import java.io.PrintWriter; public class CDMALTEPhone extends CDMAPhone { static final String LOG_TAG = "CDMA"; private static final boolean DBG = true; /** Secondary SMSDispatcher for 3GPP format messages. */ SMSDispatcher m3gppSMS; /** CdmaLtePhone in addition to RuimRecords available from * PhoneBase needs access to SIMRecords and IsimUiccRecords */ private SIMRecords mSimRecords; private IsimUiccRecords mIsimUiccRecords; /** * Small container class used to hold information relevant to * the carrier selection process. operatorNumeric can be "" * if we are looking for automatic selection. operatorAlphaLong is the * corresponding operator name. */ private static class NetworkSelectMessage { public Message message; public String operatorNumeric; public String operatorAlphaLong; } // Constructors public CDMALTEPhone(Context context, CommandsInterface ci, PhoneNotifier notifier) { super(context, ci, notifier, false); m3gppSMS = new GsmSMSDispatcher(this, mSmsStorageMonitor, mSmsUsageMonitor); } @Override public void handleMessage (Message msg) { AsyncResult ar; switch (msg.what) { // handle the select network completion callbacks. case EVENT_SET_NETWORK_MANUAL_COMPLETE: handleSetSelectNetwork((AsyncResult) msg.obj); break; case EVENT_NEW_ICC_SMS: ar = (AsyncResult)msg.obj; m3gppSMS.dispatchMessage((SmsMessage)ar.result); break; default: super.handleMessage(msg); } } @Override protected void initSstIcc() { mSST = new CdmaLteServiceStateTracker(this); } @Override public void dispose() { synchronized(PhoneProxy.lockForRadioTechnologyChange) { super.dispose(); m3gppSMS.dispose(); } } @Override public void removeReferences() { super.removeReferences(); m3gppSMS = null; } @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 (mDataConnectionTracker.isApnTypeEnabled(apnType) == false) { ret = PhoneConstants.DataState.DISCONNECTED; } else { switch (mDataConnectionTracker.getState(apnType)) { case FAILED: case IDLE: ret = PhoneConstants.DataState.DISCONNECTED; break; case CONNECTED: case DISCONNECTING: if (mCT.state != PhoneConstants.State.IDLE && !mSST.isConcurrentVoiceAndDataAllowed()) { ret = PhoneConstants.DataState.SUSPENDED; } else { ret = PhoneConstants.DataState.CONNECTED; } break; case INITING: case CONNECTING: case SCANNING: ret = PhoneConstants.DataState.CONNECTING; break; } } log("getDataConnectionState apnType=" + apnType + " ret=" + ret); return ret; } @Override public void selectNetworkManually(OperatorInfo network, Message response) { // wrap the response message in our own message along with // the operator's id. NetworkSelectMessage nsm = new NetworkSelectMessage(); nsm.message = response; nsm.operatorNumeric = network.getOperatorNumeric(); nsm.operatorAlphaLong = network.getOperatorAlphaLong(); // get the message Message msg = obtainMessage(EVENT_SET_NETWORK_MANUAL_COMPLETE, nsm); mCM.setNetworkSelectionModeManual(network.getOperatorNumeric(), msg); } /** * Used to track the settings upon completion of the network change. */ private void handleSetSelectNetwork(AsyncResult ar) { // look for our wrapper within the asyncresult, skip the rest if it // is null. if (!(ar.userObj instanceof NetworkSelectMessage)) { Log.e(LOG_TAG, "unexpected result from user object."); return; } NetworkSelectMessage nsm = (NetworkSelectMessage) ar.userObj; // found the object, now we send off the message we had originally // attached to the request. if (nsm.message != null) { if (DBG) log("sending original message to recipient"); AsyncResult.forMessage(nsm.message, ar.result, ar.exception); nsm.message.sendToTarget(); } // open the shared preferences editor, and write the value. // nsm.operatorNumeric is "" if we're in automatic.selection. SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getContext()); SharedPreferences.Editor editor = sp.edit(); editor.putString(NETWORK_SELECTION_KEY, nsm.operatorNumeric); editor.putString(NETWORK_SELECTION_NAME_KEY, nsm.operatorAlphaLong); // commit and log the result. if (! editor.commit()) { Log.e(LOG_TAG, "failed to commit network selection preference"); } } @Override public boolean updateCurrentCarrierInProvider() { if (mSimRecords != null) { try { Uri uri = Uri.withAppendedPath(Telephony.Carriers.CONTENT_URI, "current"); ContentValues map = new ContentValues(); String operatorNumeric = mSimRecords.getOperatorNumeric(); map.put(Telephony.Carriers.NUMERIC, operatorNumeric); if (DBG) log("updateCurrentCarrierInProvider from UICC: numeric=" + operatorNumeric); mContext.getContentResolver().insert(uri, map); return true; } catch (SQLException e) { Log.e(LOG_TAG, "[CDMALTEPhone] Can't store current operator ret false", e); } } else { if (DBG) log("updateCurrentCarrierInProvider mIccRecords == null ret false"); } return false; } // return IMSI from USIM as subscriber ID. @Override public String getSubscriberId() { return (mSimRecords != null) ? mSimRecords.getIMSI() : ""; } @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) { mCM.getAvailableNetworks(response); } @Override public void requestIsimAuthentication(String nonce, Message result) { mCM.requestIsimAuthentication(nonce, result); } @Override protected void onUpdateIccAvailability() { if (mUiccController == null ) { return; } // Update IsimRecords UiccCardApplication newUiccApplication = mUiccController.getUiccCardApplication(UiccController.APP_FAM_IMS); IsimUiccRecords newIsimUiccRecords = null; if (newUiccApplication != null) { newIsimUiccRecords = (IsimUiccRecords)newUiccApplication.getIccRecords(); } mIsimUiccRecords = newIsimUiccRecords; // Update UsimRecords newUiccApplication = mUiccController.getUiccCardApplication(UiccController.APP_FAM_3GPP); SIMRecords newSimRecords = null; if (newUiccApplication != null) { newSimRecords = (SIMRecords)newUiccApplication.getIccRecords(); } if (mSimRecords != newSimRecords) { if (mSimRecords != null) { log("Removing stale SIMRecords object."); mSimRecords.unregisterForNewSms(this); mSimRecords = null; } if (newSimRecords != null) { log("New SIMRecords found"); mSimRecords = newSimRecords; mSimRecords.registerForNewSms(this, EVENT_NEW_ICC_SMS, null); } } super.onUpdateIccAvailability(); } @Override protected void log(String s) { Log.d(LOG_TAG, "[CDMALTEPhone] " + s); } @Override public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { pw.println("CDMALTEPhone extends:"); super.dump(fd, pw, args); pw.println(" m3gppSMS=" + m3gppSMS); } }