1/* 2 * Copyright (C) 2011 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package com.android.internal.telephony.cdma; 18 19import android.app.ActivityManagerNative; 20import android.content.ContentValues; 21import android.content.Context; 22import android.content.Intent; 23import android.content.SharedPreferences; 24import android.database.SQLException; 25import android.net.Uri; 26import android.os.AsyncResult; 27import android.os.Handler; 28import android.os.Message; 29import android.os.UserHandle; 30import android.preference.PreferenceManager; 31import android.os.PowerManager; 32import android.os.SystemProperties; 33import android.provider.Telephony; 34import android.text.TextUtils; 35import android.telephony.SubscriptionManager; 36import android.telephony.Rlog; 37 38import com.android.internal.telephony.CommandsInterface; 39 40import android.telephony.TelephonyManager; 41 42import com.android.internal.telephony.dataconnection.DcTracker; 43import com.android.internal.telephony.MccTable; 44import com.android.internal.telephony.OperatorInfo; 45import com.android.internal.telephony.PhoneConstants; 46import com.android.internal.telephony.PhoneNotifier; 47import com.android.internal.telephony.PhoneProxy; 48import com.android.internal.telephony.PhoneFactory; 49import com.android.internal.telephony.PhoneSubInfo; 50import com.android.internal.telephony.SMSDispatcher; 51import com.android.internal.telephony.SmsBroadcastUndelivered; 52import com.android.internal.telephony.SubscriptionController; 53import com.android.internal.telephony.gsm.GsmSMSDispatcher; 54import com.android.internal.telephony.gsm.SmsMessage; 55import com.android.internal.telephony.uicc.IccRecords; 56import com.android.internal.telephony.uicc.IsimRecords; 57import com.android.internal.telephony.uicc.IsimUiccRecords; 58import com.android.internal.telephony.uicc.RuimRecords; 59import com.android.internal.telephony.uicc.SIMRecords; 60import com.android.internal.telephony.uicc.UiccCardApplication; 61import com.android.internal.telephony.uicc.UiccController; 62import com.android.internal.telephony.ServiceStateTracker; 63import com.android.internal.telephony.TelephonyIntents; 64import com.android.internal.telephony.TelephonyProperties; 65 66import java.io.FileDescriptor; 67import java.io.PrintWriter; 68 69 70public class CDMALTEPhone extends CDMAPhone { 71 static final String LOG_LTE_TAG = "CDMALTEPhone"; 72 private static final boolean DBG = true; 73 74 /** CdmaLtePhone in addition to RuimRecords available from 75 * PhoneBase needs access to SIMRecords and IsimUiccRecords 76 */ 77 private SIMRecords mSimRecords; 78 private IsimUiccRecords mIsimUiccRecords; 79 80 // Constructors 81 public CDMALTEPhone(Context context, CommandsInterface ci, PhoneNotifier notifier, 82 int phoneId) { 83 this(context, ci, notifier, false, phoneId); 84 } 85 86 public CDMALTEPhone(Context context, CommandsInterface ci, PhoneNotifier notifier, 87 boolean unitTestMode, int phoneId) { 88 super(context, ci, notifier, phoneId); 89 90 Rlog.d(LOG_TAG, "CDMALTEPhone: constructor: sub = " + mPhoneId); 91 92 mDcTracker = new DcTracker(this); 93 94 } 95 96 @Override 97 protected void initSstIcc() { 98 mSST = new CdmaLteServiceStateTracker(this); 99 } 100 101 @Override 102 public void dispose() { 103 synchronized(PhoneProxy.lockForRadioTechnologyChange) { 104 if (mSimRecords != null) { 105 mSimRecords.unregisterForRecordsLoaded(this); 106 } 107 super.dispose(); 108 } 109 } 110 111 @Override 112 public void removeReferences() { 113 super.removeReferences(); 114 } 115 116 @Override 117 public void handleMessage(Message msg) { 118 AsyncResult ar; 119 Message onComplete; 120 121 // messages to be handled whether or not the phone is being destroyed 122 // should only include messages which are being re-directed and do not use 123 // resources of the phone being destroyed 124 switch (msg.what) { 125 // handle the select network completion callbacks. 126 case EVENT_SET_NETWORK_MANUAL_COMPLETE: 127 case EVENT_SET_NETWORK_AUTOMATIC_COMPLETE: 128 super.handleMessage(msg); 129 return; 130 } 131 132 if (!mIsTheCurrentActivePhone) { 133 Rlog.e(LOG_TAG, "Received message " + msg + 134 "[" + msg.what + "] while being destroyed. Ignoring."); 135 return; 136 } 137 switch(msg.what) { 138 case EVENT_SIM_RECORDS_LOADED: 139 mSimRecordsLoadedRegistrants.notifyRegistrants(); 140 break; 141 142 default: 143 super.handleMessage(msg); 144 } 145 } 146 @Override 147 public PhoneConstants.DataState getDataConnectionState(String apnType) { 148 PhoneConstants.DataState ret = PhoneConstants.DataState.DISCONNECTED; 149 150 if (mSST == null) { 151 // Radio Technology Change is ongoing, dispose() and 152 // removeReferences() have already been called 153 154 ret = PhoneConstants.DataState.DISCONNECTED; 155 } else if (mDcTracker.isApnTypeEnabled(apnType) == false) { 156 ret = PhoneConstants.DataState.DISCONNECTED; 157 } else { 158 switch (mDcTracker.getState(apnType)) { 159 case RETRYING: 160 case FAILED: 161 case IDLE: 162 ret = PhoneConstants.DataState.DISCONNECTED; 163 break; 164 165 case CONNECTED: 166 case DISCONNECTING: 167 if (mCT.mState != PhoneConstants.State.IDLE && 168 !mSST.isConcurrentVoiceAndDataAllowed()) { 169 ret = PhoneConstants.DataState.SUSPENDED; 170 } else { 171 ret = PhoneConstants.DataState.CONNECTED; 172 } 173 break; 174 175 case CONNECTING: 176 case SCANNING: 177 ret = PhoneConstants.DataState.CONNECTING; 178 break; 179 } 180 } 181 182 log("getDataConnectionState apnType=" + apnType + " ret=" + ret); 183 return ret; 184 } 185 186 /** 187 * Sets the "current" field in the telephony provider according to the 188 * build-time operator numeric property 189 * 190 * @return true for success; false otherwise. 191 */ 192 @Override 193 boolean updateCurrentCarrierInProvider(String operatorNumeric) { 194 boolean retVal; 195 if (mUiccController.getUiccCardApplication(mPhoneId, UiccController.APP_FAM_3GPP) == null) { 196 if (DBG) log("updateCurrentCarrierInProvider APP_FAM_3GPP == null"); 197 retVal = super.updateCurrentCarrierInProvider(operatorNumeric); 198 } else { 199 if (DBG) log("updateCurrentCarrierInProvider not updated"); 200 retVal = true; 201 } 202 if (DBG) log("updateCurrentCarrierInProvider X retVal=" + retVal); 203 return retVal; 204 } 205 206 @Override 207 public boolean updateCurrentCarrierInProvider() { 208 long currentDds = SubscriptionManager.getDefaultDataSubId(); 209 String operatorNumeric = getOperatorNumeric(); 210 211 Rlog.d(LOG_TAG, "updateCurrentCarrierInProvider: mSubscription = " + getSubId() 212 + " currentDds = " + currentDds + " operatorNumeric = " + operatorNumeric); 213 214 if (!TextUtils.isEmpty(operatorNumeric) && (getSubId() == currentDds)) { 215 try { 216 Uri uri = Uri.withAppendedPath(Telephony.Carriers.CONTENT_URI, "current"); 217 ContentValues map = new ContentValues(); 218 map.put(Telephony.Carriers.NUMERIC, operatorNumeric); 219 mContext.getContentResolver().insert(uri, map); 220 return true; 221 } catch (SQLException e) { 222 Rlog.e(LOG_TAG, "Can't store current operator", e); 223 } 224 } 225 return false; 226 } 227 228 // return IMSI from USIM as subscriber ID. 229 @Override 230 public String getSubscriberId() { 231 return (mSimRecords != null) ? mSimRecords.getIMSI() : ""; 232 } 233 234 // return GID1 from USIM 235 @Override 236 public String getGroupIdLevel1() { 237 return (mSimRecords != null) ? mSimRecords.getGid1() : ""; 238 } 239 240 @Override 241 public String getImei() { 242 return mImei; 243 } 244 245 @Override 246 public String getDeviceSvn() { 247 return mImeiSv; 248 } 249 250 @Override 251 public IsimRecords getIsimRecords() { 252 return mIsimUiccRecords; 253 } 254 255 @Override 256 public String getMsisdn() { 257 return (mSimRecords != null) ? mSimRecords.getMsisdnNumber() : null; 258 } 259 260 @Override 261 public void getAvailableNetworks(Message response) { 262 mCi.getAvailableNetworks(response); 263 } 264 265 @Override 266 protected void onUpdateIccAvailability() { 267 if (mSimRecords != null) { 268 mSimRecords.unregisterForRecordsLoaded(this); 269 } 270 271 if (mUiccController == null ) { 272 return; 273 } 274 275 // Update IsimRecords 276 UiccCardApplication newUiccApplication = 277 mUiccController.getUiccCardApplication(mPhoneId, UiccController.APP_FAM_IMS); 278 IsimUiccRecords newIsimUiccRecords = null; 279 280 if (newUiccApplication != null) { 281 newIsimUiccRecords = (IsimUiccRecords) newUiccApplication.getIccRecords(); 282 } 283 mIsimUiccRecords = newIsimUiccRecords; 284 285 // Update UsimRecords 286 newUiccApplication = mUiccController.getUiccCardApplication(mPhoneId, 287 UiccController.APP_FAM_3GPP); 288 SIMRecords newSimRecords = null; 289 if (newUiccApplication != null) { 290 newSimRecords = (SIMRecords) newUiccApplication.getIccRecords(); 291 } 292 mSimRecords = newSimRecords; 293 if (mSimRecords != null) { 294 mSimRecords.registerForRecordsLoaded(this, EVENT_SIM_RECORDS_LOADED, null); 295 } 296 297 super.onUpdateIccAvailability(); 298 } 299 300 @Override 301 protected void init(Context context, PhoneNotifier notifier) { 302 mCi.setPhoneType(PhoneConstants.PHONE_TYPE_CDMA); 303 mCT = new CdmaCallTracker(this); 304 mCdmaSSM = CdmaSubscriptionSourceManager.getInstance(context, mCi, this, 305 EVENT_CDMA_SUBSCRIPTION_SOURCE_CHANGED, null); 306 mRuimPhoneBookInterfaceManager = new RuimPhoneBookInterfaceManager(this); 307 mSubInfo = new PhoneSubInfo(this); 308 mEriManager = new EriManager(this, context, EriManager.ERI_FROM_XML); 309 310 mCi.registerForAvailable(this, EVENT_RADIO_AVAILABLE, null); 311 mCi.registerForOffOrNotAvailable(this, EVENT_RADIO_OFF_OR_NOT_AVAILABLE, null); 312 mCi.registerForOn(this, EVENT_RADIO_ON, null); 313 mCi.setOnSuppServiceNotification(this, EVENT_SSN, null); 314 mSST.registerForNetworkAttached(this, EVENT_REGISTERED_TO_NETWORK, null); 315 mCi.setEmergencyCallbackMode(this, EVENT_EMERGENCY_CALLBACK_MODE_ENTER, null); 316 mCi.registerForExitEmergencyCallbackMode(this, EVENT_EXIT_EMERGENCY_CALLBACK_RESPONSE, 317 null); 318 319 PowerManager pm 320 = (PowerManager) context.getSystemService(Context.POWER_SERVICE); 321 mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,LOG_TAG); 322 323 // This is needed to handle phone process crashes 324 String inEcm = SystemProperties.get(TelephonyProperties.PROPERTY_INECM_MODE, "false"); 325 mIsPhoneInEcmState = inEcm.equals("true"); 326 if (mIsPhoneInEcmState) { 327 // Send a message which will invoke handleExitEmergencyCallbackMode 328 mCi.exitEmergencyCallbackMode(obtainMessage(EVENT_EXIT_EMERGENCY_CALLBACK_RESPONSE)); 329 } 330 331 // get the string that specifies the carrier OTA Sp number 332 mCarrierOtaSpNumSchema = TelephonyManager.from(mContext).getOtaSpNumberSchemaForPhone( 333 getPhoneId(), ""); 334 335 setProperties(); 336 } 337 338 // Set the properties per subscription 339 private void setProperties() { 340 TelephonyManager tm = TelephonyManager.from(mContext); 341 //Change the system property 342 tm.setPhoneType(getPhoneId(), PhoneConstants.PHONE_TYPE_CDMA); 343 // Sets operator alpha property by retrieving from build-time system property 344 String operatorAlpha = SystemProperties.get("ro.cdma.home.operator.alpha"); 345 if (!TextUtils.isEmpty(operatorAlpha)) { 346 tm.setSimOperatorNameForPhone(getPhoneId(), operatorAlpha); 347 } 348 349 // Sets operator numeric property by retrieving from build-time system property 350 String operatorNumeric = SystemProperties.get(PROPERTY_CDMA_HOME_OPERATOR_NUMERIC); 351 log("update icc_operator_numeric=" + operatorNumeric); 352 if (!TextUtils.isEmpty(operatorNumeric)) { 353 tm.setSimOperatorNumericForPhone(getPhoneId(), operatorNumeric); 354 355 SubscriptionController.getInstance().setMccMnc(operatorNumeric, getSubId()); 356 // Sets iso country property by retrieving from build-time system property 357 setIsoCountryProperty(operatorNumeric); 358 // Updates MCC MNC device configuration information 359 log("update mccmnc=" + operatorNumeric); 360 MccTable.updateMccMncConfiguration(mContext, operatorNumeric, false); 361 } 362 // Sets current entry in the telephony carrier table 363 updateCurrentCarrierInProvider(); 364 } 365 366 @Override 367 public void setSystemProperty(String property, String value) { 368 if(getUnitTestMode()) { 369 return; 370 } 371 TelephonyManager.setTelephonyProperty(mPhoneId, property, value); 372 } 373 374 public String getSystemProperty(String property, String defValue) { 375 if(getUnitTestMode()) { 376 return null; 377 } 378 return TelephonyManager.getTelephonyProperty(mPhoneId, property, defValue); 379 } 380 381 public void updateDataConnectionTracker() { 382 ((DcTracker)mDcTracker).update(); 383 } 384 385 public void setInternalDataEnabled(boolean enable, Message onCompleteMsg) { 386 ((DcTracker)mDcTracker) 387 .setInternalDataEnabled(enable, onCompleteMsg); 388 } 389 390 public boolean setInternalDataEnabledFlag(boolean enable) { 391 return ((DcTracker)mDcTracker) 392 .setInternalDataEnabledFlag(enable); 393 } 394 395 /** 396 * @return operator numeric. 397 */ 398 public String getOperatorNumeric() { 399 String operatorNumeric = null; 400 IccRecords curIccRecords = null; 401 if (mCdmaSubscriptionSource == CDMA_SUBSCRIPTION_NV) { 402 operatorNumeric = SystemProperties.get("ro.cdma.home.operator.numeric"); 403 } else if (mCdmaSubscriptionSource == CDMA_SUBSCRIPTION_RUIM_SIM) { 404 curIccRecords = mSimRecords; 405 if (curIccRecords != null) { 406 operatorNumeric = curIccRecords.getOperatorNumeric(); 407 } else { 408 curIccRecords = mIccRecords.get(); 409 if (curIccRecords != null && (curIccRecords instanceof RuimRecords)) { 410 RuimRecords csim = (RuimRecords) curIccRecords; 411 operatorNumeric = csim.getRUIMOperatorNumeric(); 412 } 413 } 414 } 415 if (operatorNumeric == null) { 416 Rlog.e(LOG_TAG, "getOperatorNumeric: Cannot retrieve operatorNumeric:" 417 + " mCdmaSubscriptionSource = " + mCdmaSubscriptionSource + " mIccRecords = " 418 + ((curIccRecords != null) ? curIccRecords.getRecordsLoaded() : null)); 419 } 420 421 Rlog.d(LOG_TAG, "getOperatorNumeric: mCdmaSubscriptionSource = " + mCdmaSubscriptionSource 422 + " operatorNumeric = " + operatorNumeric); 423 424 return operatorNumeric; 425 } 426 public void registerForAllDataDisconnected(Handler h, int what, Object obj) { 427 ((DcTracker)mDcTracker) 428 .registerForAllDataDisconnected(h, what, obj); 429 } 430 431 public void unregisterForAllDataDisconnected(Handler h) { 432 ((DcTracker)mDcTracker) 433 .unregisterForAllDataDisconnected(h); 434 } 435 436 @Override 437 public void registerForSimRecordsLoaded(Handler h, int what, Object obj) { 438 mSimRecordsLoadedRegistrants.addUnique(h, what, obj); 439 } 440 441 @Override 442 public void unregisterForSimRecordsLoaded(Handler h) { 443 mSimRecordsLoadedRegistrants.remove(h); 444 } 445 446 447 @Override 448 protected void log(String s) { 449 Rlog.d(LOG_LTE_TAG, s); 450 } 451 452 protected void loge(String s) { 453 Rlog.e(LOG_LTE_TAG, s); 454 } 455 456 protected void loge(String s, Throwable e) { 457 Rlog.e(LOG_LTE_TAG, s, e); 458 } 459 460 @Override 461 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 462 pw.println("CDMALTEPhone extends:"); 463 super.dump(fd, pw, args); 464 } 465} 466