1 /* 2 * Copyright (C) 2006 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 17 package com.android.phone; 18 19 import android.app.Activity; 20 import android.app.KeyguardManager; 21 import android.app.ProgressDialog; 22 import android.content.BroadcastReceiver; 23 import android.content.ContentResolver; 24 import android.content.Context; 25 import android.content.ContextWrapper; 26 import android.content.Intent; 27 import android.content.IntentFilter; 28 import android.content.res.XmlResourceParser; 29 import android.media.AudioManager; 30 import android.net.ConnectivityManager; 31 import android.net.Uri; 32 import android.net.sip.SipManager; 33 import android.os.AsyncResult; 34 import android.os.Bundle; 35 import android.os.Handler; 36 import android.os.Message; 37 import android.os.PersistableBundle; 38 import android.os.PowerManager; 39 import android.os.SystemClock; 40 import android.os.SystemProperties; 41 import android.os.UpdateLock; 42 import android.os.UserManager; 43 import android.preference.PreferenceManager; 44 import android.provider.Settings; 45 import android.telecom.TelecomManager; 46 import android.telephony.AnomalyReporter; 47 import android.telephony.CarrierConfigManager; 48 import android.telephony.ServiceState; 49 import android.telephony.SubscriptionManager; 50 import android.telephony.TelephonyManager; 51 import android.telephony.data.ApnSetting; 52 import android.util.LocalLog; 53 import android.util.Log; 54 import android.widget.Toast; 55 56 import com.android.internal.telephony.CallManager; 57 import com.android.internal.telephony.IccCardConstants; 58 import com.android.internal.telephony.MmiCode; 59 import com.android.internal.telephony.Phone; 60 import com.android.internal.telephony.PhoneConstants; 61 import com.android.internal.telephony.PhoneFactory; 62 import com.android.internal.telephony.SettingsObserver; 63 import com.android.internal.telephony.TelephonyCapabilities; 64 import com.android.internal.telephony.TelephonyComponentFactory; 65 import com.android.internal.telephony.TelephonyIntents; 66 import com.android.internal.telephony.dataconnection.DataConnectionReasons; 67 import com.android.internal.telephony.dataconnection.DataConnectionReasons.DataDisallowedReasonType; 68 import com.android.internal.util.IndentingPrintWriter; 69 import com.android.phone.settings.SettingsConstants; 70 import com.android.phone.vvm.CarrierVvmPackageInstalledReceiver; 71 import com.android.services.telephony.sip.SipAccountRegistry; 72 import com.android.services.telephony.sip.SipUtil; 73 74 import java.io.FileDescriptor; 75 import java.io.PrintWriter; 76 77 /** 78 * Global state for the telephony subsystem when running in the primary 79 * phone process. 80 */ 81 public class PhoneGlobals extends ContextWrapper { 82 public static final String LOG_TAG = "PhoneGlobals"; 83 84 /** 85 * Phone app-wide debug level: 86 * 0 - no debug logging 87 * 1 - normal debug logging if ro.debuggable is set (which is true in 88 * "eng" and "userdebug" builds but not "user" builds) 89 * 2 - ultra-verbose debug logging 90 * 91 * Most individual classes in the phone app have a local DBG constant, 92 * typically set to 93 * (PhoneApp.DBG_LEVEL >= 1) && (SystemProperties.getInt("ro.debuggable", 0) == 1) 94 * or else 95 * (PhoneApp.DBG_LEVEL >= 2) 96 * depending on the desired verbosity. 97 * 98 * ***** DO NOT SUBMIT WITH DBG_LEVEL > 0 ************* 99 */ 100 public static final int DBG_LEVEL = 0; 101 102 private static final boolean DBG = 103 (PhoneGlobals.DBG_LEVEL >= 1) && (SystemProperties.getInt("ro.debuggable", 0) == 1); 104 private static final boolean VDBG = (PhoneGlobals.DBG_LEVEL >= 2); 105 106 // Message codes; see mHandler below. 107 private static final int EVENT_SIM_NETWORK_LOCKED = 3; 108 private static final int EVENT_SIM_STATE_CHANGED = 8; 109 private static final int EVENT_DATA_ROAMING_DISCONNECTED = 10; 110 private static final int EVENT_DATA_ROAMING_OK = 11; 111 private static final int EVENT_UNSOL_CDMA_INFO_RECORD = 12; 112 private static final int EVENT_RESTART_SIP = 13; 113 private static final int EVENT_DATA_ROAMING_SETTINGS_CHANGED = 14; 114 private static final int EVENT_MOBILE_DATA_SETTINGS_CHANGED = 15; 115 116 // The MMI codes are also used by the InCallScreen. 117 public static final int MMI_INITIATE = 51; 118 public static final int MMI_COMPLETE = 52; 119 public static final int MMI_CANCEL = 53; 120 // Don't use message codes larger than 99 here; those are reserved for 121 // the individual Activities of the Phone UI. 122 123 public static final int AIRPLANE_ON = 1; 124 public static final int AIRPLANE_OFF = 0; 125 126 /** 127 * Allowable values for the wake lock code. 128 * SLEEP means the device can be put to sleep. 129 * PARTIAL means wake the processor, but we display can be kept off. 130 * FULL means wake both the processor and the display. 131 */ 132 public enum WakeState { 133 SLEEP, 134 PARTIAL, 135 FULL 136 } 137 138 private static PhoneGlobals sMe; 139 140 CallManager mCM; 141 CallNotifier notifier; 142 CallerInfoCache callerInfoCache; 143 NotificationMgr notificationMgr; 144 public PhoneInterfaceManager phoneMgr; 145 CarrierConfigLoader configLoader; 146 147 private Phone phoneInEcm; 148 149 static boolean sVoiceCapable = true; 150 151 // TODO: Remove, no longer used. 152 CdmaPhoneCallState cdmaPhoneCallState; 153 154 // The currently-active PUK entry activity and progress dialog. 155 // Normally, these are the Emergency Dialer and the subsequent 156 // progress dialog. null if there is are no such objects in 157 // the foreground. 158 private Activity mPUKEntryActivity; 159 private ProgressDialog mPUKEntryProgressDialog; 160 161 private boolean mNoDataDueToRoaming = false; 162 163 private WakeState mWakeState = WakeState.SLEEP; 164 165 private PowerManager mPowerManager; 166 private PowerManager.WakeLock mWakeLock; 167 private PowerManager.WakeLock mPartialWakeLock; 168 private KeyguardManager mKeyguardManager; 169 170 private UpdateLock mUpdateLock; 171 172 private int mDefaultDataSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID; 173 private final LocalLog mDataRoamingNotifLog = new LocalLog(50); 174 175 // Broadcast receiver for various intent broadcasts (see onCreate()) 176 private final BroadcastReceiver mReceiver = new PhoneAppBroadcastReceiver(); 177 // Broadcast receiver for SIP based intents (see onCreate()) 178 private final SipReceiver mSipReceiver = new SipReceiver(); 179 180 private final CarrierVvmPackageInstalledReceiver mCarrierVvmPackageInstalledReceiver = 181 new CarrierVvmPackageInstalledReceiver(); 182 183 private final SettingsObserver mSettingsObserver; 184 185 Handler mHandler = new Handler() { 186 @Override 187 public void handleMessage(Message msg) { 188 PhoneConstants.State phoneState; 189 if (VDBG) Log.v(LOG_TAG, "event=" + msg.what); 190 switch (msg.what) { 191 // TODO: This event should be handled by the lock screen, just 192 // like the "SIM missing" and "Sim locked" cases (bug 1804111). 193 case EVENT_SIM_NETWORK_LOCKED: 194 if (getCarrierConfig().getBoolean( 195 CarrierConfigManager.KEY_IGNORE_SIM_NETWORK_LOCKED_EVENTS_BOOL)) { 196 // Some products don't have the concept of a "SIM network lock" 197 Log.i(LOG_TAG, "Ignoring EVENT_SIM_NETWORK_LOCKED event; " 198 + "not showing 'SIM network unlock' PIN entry screen"); 199 } else { 200 // Normal case: show the "SIM network unlock" PIN entry screen. 201 // The user won't be able to do anything else until 202 // they enter a valid SIM network PIN. 203 Log.i(LOG_TAG, "show sim depersonal panel"); 204 Phone phone = (Phone) ((AsyncResult) msg.obj).userObj; 205 IccNetworkDepersonalizationPanel.showDialog(phone); 206 } 207 break; 208 209 case EVENT_DATA_ROAMING_DISCONNECTED: 210 notificationMgr.showDataDisconnectedRoaming(msg.arg1); 211 break; 212 213 case EVENT_DATA_ROAMING_OK: 214 notificationMgr.hideDataDisconnectedRoaming(); 215 break; 216 217 case MMI_COMPLETE: 218 onMMIComplete((AsyncResult) msg.obj); 219 break; 220 221 case MMI_CANCEL: 222 PhoneUtils.cancelMmiCode(mCM.getFgPhone()); 223 break; 224 225 case EVENT_SIM_STATE_CHANGED: 226 // Marks the event where the SIM goes into ready state. 227 // Right now, this is only used for the PUK-unlocking 228 // process. 229 if (msg.obj.equals(IccCardConstants.INTENT_VALUE_ICC_READY) 230 || msg.obj.equals(IccCardConstants.INTENT_VALUE_ICC_LOADED)) { 231 // when the right event is triggered and there 232 // are UI objects in the foreground, we close 233 // them to display the lock panel. 234 if (mPUKEntryActivity != null) { 235 mPUKEntryActivity.finish(); 236 mPUKEntryActivity = null; 237 } 238 if (mPUKEntryProgressDialog != null) { 239 mPUKEntryProgressDialog.dismiss(); 240 mPUKEntryProgressDialog = null; 241 } 242 } 243 break; 244 245 case EVENT_UNSOL_CDMA_INFO_RECORD: 246 //TODO: handle message here; 247 break; 248 case EVENT_RESTART_SIP: 249 // This should only run if the Phone process crashed and was restarted. We do 250 // not want this running if the device is still in the FBE encrypted state. 251 // This is the same procedure that is triggered in the SipIncomingCallReceiver 252 // upon BOOT_COMPLETED. 253 UserManager userManager = UserManager.get(sMe); 254 if (userManager != null && userManager.isUserUnlocked()) { 255 SipUtil.startSipService(); 256 } 257 break; 258 case EVENT_DATA_ROAMING_SETTINGS_CHANGED: 259 case EVENT_MOBILE_DATA_SETTINGS_CHANGED: 260 updateDataRoamingStatus(); 261 break; 262 } 263 } 264 }; 265 PhoneGlobals(Context context)266 public PhoneGlobals(Context context) { 267 super(context); 268 sMe = this; 269 mSettingsObserver = new SettingsObserver(context, mHandler); 270 } 271 onCreate()272 public void onCreate() { 273 if (VDBG) Log.v(LOG_TAG, "onCreate()..."); 274 275 ContentResolver resolver = getContentResolver(); 276 277 // Cache the "voice capable" flag. 278 // This flag currently comes from a resource (which is 279 // overrideable on a per-product basis): 280 sVoiceCapable = 281 getResources().getBoolean(com.android.internal.R.bool.config_voice_capable); 282 // ...but this might eventually become a PackageManager "system 283 // feature" instead, in which case we'd do something like: 284 // sVoiceCapable = 285 // getPackageManager().hasSystemFeature(PackageManager.FEATURE_TELEPHONY_VOICE_CALLS); 286 287 if (mCM == null) { 288 // Initialize AnomalyReporter early so that it can be used 289 AnomalyReporter.initialize(this); 290 291 // Inject telephony component factory if configured using other jars. 292 XmlResourceParser parser = getResources().getXml(R.xml.telephony_injection); 293 TelephonyComponentFactory.getInstance().injectTheComponentFactory(parser); 294 // Initialize the telephony framework 295 PhoneFactory.makeDefaultPhones(this); 296 297 // Start TelephonyDebugService After the default phone is created. 298 Intent intent = new Intent(this, TelephonyDebugService.class); 299 startService(intent); 300 301 mCM = CallManager.getInstance(); 302 for (Phone phone : PhoneFactory.getPhones()) { 303 mCM.registerPhone(phone); 304 } 305 306 // Create the NotificationMgr singleton, which is used to display 307 // status bar icons and control other status bar behavior. 308 notificationMgr = NotificationMgr.init(this); 309 310 // If PhoneGlobals has crashed and is being restarted, then restart. 311 mHandler.sendEmptyMessage(EVENT_RESTART_SIP); 312 313 // Create an instance of CdmaPhoneCallState and initialize it to IDLE 314 cdmaPhoneCallState = new CdmaPhoneCallState(); 315 cdmaPhoneCallState.CdmaPhoneCallStateInit(); 316 317 // before registering for phone state changes 318 mPowerManager = (PowerManager) getSystemService(Context.POWER_SERVICE); 319 mWakeLock = mPowerManager.newWakeLock(PowerManager.FULL_WAKE_LOCK, LOG_TAG); 320 // lock used to keep the processor awake, when we don't care for the display. 321 mPartialWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK 322 | PowerManager.ON_AFTER_RELEASE, LOG_TAG); 323 324 mKeyguardManager = (KeyguardManager) getSystemService(Context.KEYGUARD_SERVICE); 325 326 // Get UpdateLock to suppress system-update related events (e.g. dialog show-up) 327 // during phone calls. 328 mUpdateLock = new UpdateLock("phone"); 329 330 if (DBG) Log.d(LOG_TAG, "onCreate: mUpdateLock: " + mUpdateLock); 331 332 // Create the CallerInfoCache singleton, which remembers custom ring tone and 333 // send-to-voicemail settings. 334 // 335 // The asynchronous caching will start just after this call. 336 callerInfoCache = CallerInfoCache.init(this); 337 338 phoneMgr = PhoneInterfaceManager.init(this); 339 340 configLoader = CarrierConfigLoader.init(this); 341 342 // Create the CallNotifier singleton, which handles 343 // asynchronous events from the telephony layer (like 344 // launching the incoming-call UI when an incoming call comes 345 // in.) 346 notifier = CallNotifier.init(this); 347 348 PhoneUtils.registerIccStatus(mHandler, EVENT_SIM_NETWORK_LOCKED); 349 350 // register for MMI/USSD 351 mCM.registerForMmiComplete(mHandler, MMI_COMPLETE, null); 352 353 // Register for misc other intent broadcasts. 354 IntentFilter intentFilter = 355 new IntentFilter(Intent.ACTION_AIRPLANE_MODE_CHANGED); 356 intentFilter.addAction(TelephonyIntents.ACTION_SIM_STATE_CHANGED); 357 intentFilter.addAction(TelephonyIntents.ACTION_RADIO_TECHNOLOGY_CHANGED); 358 intentFilter.addAction(TelephonyIntents.ACTION_SERVICE_STATE_CHANGED); 359 intentFilter.addAction(TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED); 360 intentFilter.addAction(TelephonyIntents.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED); 361 intentFilter.addAction(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED); 362 registerReceiver(mReceiver, intentFilter); 363 364 IntentFilter sipIntentFilter = new IntentFilter(Intent.ACTION_BOOT_COMPLETED); 365 sipIntentFilter.addAction(SipManager.ACTION_SIP_SERVICE_UP); 366 sipIntentFilter.addAction(SipManager.ACTION_SIP_CALL_OPTION_CHANGED); 367 sipIntentFilter.addAction(SipManager.ACTION_SIP_REMOVE_PHONE); 368 registerReceiver(mSipReceiver, sipIntentFilter); 369 370 mCarrierVvmPackageInstalledReceiver.register(this); 371 372 //set the default values for the preferences in the phone. 373 PreferenceManager.setDefaultValues(this, R.xml.network_setting_fragment, false); 374 375 PreferenceManager.setDefaultValues(this, R.xml.call_feature_setting, false); 376 } 377 378 // XXX pre-load the SimProvider so that it's ready 379 resolver.getType(Uri.parse("content://icc/adn")); 380 381 // TODO: Register for Cdma Information Records 382 // phone.registerCdmaInformationRecord(mHandler, EVENT_UNSOL_CDMA_INFO_RECORD, null); 383 384 // Read HAC settings and configure audio hardware 385 if (getResources().getBoolean(R.bool.hac_enabled)) { 386 int hac = android.provider.Settings.System.getInt( 387 getContentResolver(), 388 android.provider.Settings.System.HEARING_AID, 389 0); 390 AudioManager audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE); 391 audioManager.setParameter(SettingsConstants.HAC_KEY, 392 hac == SettingsConstants.HAC_ENABLED 393 ? SettingsConstants.HAC_VAL_ON : SettingsConstants.HAC_VAL_OFF); 394 } 395 } 396 397 /** 398 * Returns the singleton instance of the PhoneApp. 399 */ getInstance()400 public static PhoneGlobals getInstance() { 401 if (sMe == null) { 402 throw new IllegalStateException("No PhoneGlobals here!"); 403 } 404 return sMe; 405 } 406 407 /** 408 * Returns the default phone. 409 * 410 * WARNING: This method should be used carefully, now that there may be multiple phones. 411 */ getPhone()412 public static Phone getPhone() { 413 return PhoneFactory.getDefaultPhone(); 414 } 415 getPhone(int subId)416 public static Phone getPhone(int subId) { 417 return PhoneFactory.getPhone(SubscriptionManager.getPhoneId(subId)); 418 } 419 getCallManager()420 /* package */ CallManager getCallManager() { 421 return mCM; 422 } 423 getCarrierConfig()424 public PersistableBundle getCarrierConfig() { 425 return getCarrierConfigForSubId(SubscriptionManager.getDefaultSubscriptionId()); 426 } 427 getCarrierConfigForSubId(int subId)428 public PersistableBundle getCarrierConfigForSubId(int subId) { 429 return configLoader.getConfigForSubId(subId, getOpPackageName()); 430 } 431 registerSettingsObserver()432 private void registerSettingsObserver() { 433 mSettingsObserver.unobserve(); 434 String dataRoamingSetting = Settings.Global.DATA_ROAMING; 435 String mobileDataSetting = Settings.Global.MOBILE_DATA; 436 if (TelephonyManager.getDefault().getSimCount() > 1) { 437 int subId = mDefaultDataSubId; 438 if (subId != SubscriptionManager.INVALID_SUBSCRIPTION_ID) { 439 dataRoamingSetting += subId; 440 mobileDataSetting += subId; 441 } 442 } 443 444 // Listen for user data roaming setting changed event 445 mSettingsObserver.observe(Settings.Global.getUriFor(dataRoamingSetting), 446 EVENT_DATA_ROAMING_SETTINGS_CHANGED); 447 448 // Listen for mobile data setting changed event 449 mSettingsObserver.observe(Settings.Global.getUriFor(mobileDataSetting), 450 EVENT_MOBILE_DATA_SETTINGS_CHANGED); 451 } 452 453 /** 454 * Sets the activity responsible for un-PUK-blocking the device 455 * so that we may close it when we receive a positive result. 456 * mPUKEntryActivity is also used to indicate to the device that 457 * we are trying to un-PUK-lock the phone. In other words, iff 458 * it is NOT null, then we are trying to unlock and waiting for 459 * the SIM to move to READY state. 460 * 461 * @param activity is the activity to close when PUK has 462 * finished unlocking. Can be set to null to indicate the unlock 463 * or SIM READYing process is over. 464 */ setPukEntryActivity(Activity activity)465 void setPukEntryActivity(Activity activity) { 466 mPUKEntryActivity = activity; 467 } 468 getPUKEntryActivity()469 Activity getPUKEntryActivity() { 470 return mPUKEntryActivity; 471 } 472 473 /** 474 * Sets the dialog responsible for notifying the user of un-PUK- 475 * blocking - SIM READYing progress, so that we may dismiss it 476 * when we receive a positive result. 477 * 478 * @param dialog indicates the progress dialog informing the user 479 * of the state of the device. Dismissed upon completion of 480 * READYing process 481 */ setPukEntryProgressDialog(ProgressDialog dialog)482 void setPukEntryProgressDialog(ProgressDialog dialog) { 483 mPUKEntryProgressDialog = dialog; 484 } 485 486 /** 487 * If we are not currently keeping the screen on, then poke the power 488 * manager to wake up the screen for the user activity timeout duration. 489 */ wakeUpScreen()490 /* package */ void wakeUpScreen() { 491 synchronized (this) { 492 if (mWakeState == WakeState.SLEEP) { 493 if (DBG) Log.d(LOG_TAG, "pulse screen lock"); 494 mPowerManager.wakeUp(SystemClock.uptimeMillis(), "android.phone:WAKE"); 495 } 496 } 497 } 498 getKeyguardManager()499 KeyguardManager getKeyguardManager() { 500 return mKeyguardManager; 501 } 502 onMMIComplete(AsyncResult r)503 private void onMMIComplete(AsyncResult r) { 504 if (VDBG) Log.d(LOG_TAG, "onMMIComplete()..."); 505 MmiCode mmiCode = (MmiCode) r.result; 506 PhoneUtils.displayMMIComplete(mmiCode.getPhone(), getInstance(), mmiCode, null, null); 507 } 508 initForNewRadioTechnology()509 private void initForNewRadioTechnology() { 510 if (DBG) Log.d(LOG_TAG, "initForNewRadioTechnology..."); 511 notifier.updateCallNotifierRegistrationsAfterRadioTechnologyChange(); 512 } 513 handleAirplaneModeChange(Context context, int newMode)514 private void handleAirplaneModeChange(Context context, int newMode) { 515 int cellState = Settings.Global.getInt(context.getContentResolver(), 516 Settings.Global.CELL_ON, PhoneConstants.CELL_ON_FLAG); 517 boolean isAirplaneNewlyOn = (newMode == 1); 518 switch (cellState) { 519 case PhoneConstants.CELL_OFF_FLAG: 520 // Airplane mode does not affect the cell radio if user 521 // has turned it off. 522 break; 523 case PhoneConstants.CELL_ON_FLAG: 524 maybeTurnCellOff(context, isAirplaneNewlyOn); 525 break; 526 case PhoneConstants.CELL_OFF_DUE_TO_AIRPLANE_MODE_FLAG: 527 maybeTurnCellOn(context, isAirplaneNewlyOn); 528 break; 529 } 530 } 531 532 /* 533 * Returns true if the radio must be turned off when entering airplane mode. 534 */ isCellOffInAirplaneMode(Context context)535 private boolean isCellOffInAirplaneMode(Context context) { 536 String airplaneModeRadios = Settings.Global.getString(context.getContentResolver(), 537 Settings.Global.AIRPLANE_MODE_RADIOS); 538 return airplaneModeRadios == null 539 || airplaneModeRadios.contains(Settings.Global.RADIO_CELL); 540 } 541 setRadioPowerOff(Context context)542 private void setRadioPowerOff(Context context) { 543 Log.i(LOG_TAG, "Turning radio off - airplane"); 544 Settings.Global.putInt(context.getContentResolver(), Settings.Global.CELL_ON, 545 PhoneConstants.CELL_OFF_DUE_TO_AIRPLANE_MODE_FLAG); 546 SystemProperties.set("persist.radio.airplane_mode_on", "1"); 547 Settings.Global.putInt(getContentResolver(), Settings.Global.ENABLE_CELLULAR_ON_BOOT, 0); 548 PhoneUtils.setRadioPower(false); 549 } 550 setRadioPowerOn(Context context)551 private void setRadioPowerOn(Context context) { 552 Log.i(LOG_TAG, "Turning radio on - airplane"); 553 Settings.Global.putInt(context.getContentResolver(), Settings.Global.CELL_ON, 554 PhoneConstants.CELL_ON_FLAG); 555 Settings.Global.putInt(getContentResolver(), Settings.Global.ENABLE_CELLULAR_ON_BOOT, 556 1); 557 SystemProperties.set("persist.radio.airplane_mode_on", "0"); 558 PhoneUtils.setRadioPower(true); 559 } 560 maybeTurnCellOff(Context context, boolean isAirplaneNewlyOn)561 private void maybeTurnCellOff(Context context, boolean isAirplaneNewlyOn) { 562 if (isAirplaneNewlyOn) { 563 // If we are trying to turn off the radio, make sure there are no active 564 // emergency calls. If there are, switch airplane mode back to off. 565 TelecomManager tm = (TelecomManager) context.getSystemService(TELECOM_SERVICE); 566 567 if (tm != null && tm.isInEmergencyCall()) { 568 // Switch airplane mode back to off. 569 ConnectivityManager.from(this).setAirplaneMode(false); 570 Toast.makeText(this, R.string.radio_off_during_emergency_call, Toast.LENGTH_LONG) 571 .show(); 572 Log.i(LOG_TAG, "Ignoring airplane mode: emergency call. Turning airplane off"); 573 } else if (isCellOffInAirplaneMode(context)) { 574 setRadioPowerOff(context); 575 } else { 576 Log.i(LOG_TAG, "Ignoring airplane mode: settings prevent cell radio power off"); 577 } 578 } 579 } 580 maybeTurnCellOn(Context context, boolean isAirplaneNewlyOn)581 private void maybeTurnCellOn(Context context, boolean isAirplaneNewlyOn) { 582 if (!isAirplaneNewlyOn) { 583 setRadioPowerOn(context); 584 } 585 } 586 587 /** 588 * Receiver for misc intent broadcasts the Phone app cares about. 589 */ 590 private class PhoneAppBroadcastReceiver extends BroadcastReceiver { 591 @Override onReceive(Context context, Intent intent)592 public void onReceive(Context context, Intent intent) { 593 String action = intent.getAction(); 594 if (action.equals(Intent.ACTION_AIRPLANE_MODE_CHANGED)) { 595 int airplaneMode = Settings.Global.getInt(getContentResolver(), 596 Settings.Global.AIRPLANE_MODE_ON, AIRPLANE_OFF); 597 // Treat any non-OFF values as ON. 598 if (airplaneMode != AIRPLANE_OFF) { 599 airplaneMode = AIRPLANE_ON; 600 } 601 handleAirplaneModeChange(context, airplaneMode); 602 } else if (action.equals(TelephonyIntents.ACTION_SIM_STATE_CHANGED)) { 603 // re-register as it may be a new IccCard 604 int phoneId = intent.getIntExtra(PhoneConstants.PHONE_KEY, 605 SubscriptionManager.INVALID_PHONE_INDEX); 606 if (SubscriptionManager.isValidPhoneId(phoneId)) { 607 PhoneUtils.unregisterIccStatus(mHandler, phoneId); 608 PhoneUtils.registerIccStatus(mHandler, EVENT_SIM_NETWORK_LOCKED, phoneId); 609 } 610 if (mPUKEntryActivity != null) { 611 // if an attempt to un-PUK-lock the device was made, while we're 612 // receiving this state change notification, notify the handler. 613 // NOTE: This is ONLY triggered if an attempt to un-PUK-lock has 614 // been attempted. 615 mHandler.sendMessage(mHandler.obtainMessage(EVENT_SIM_STATE_CHANGED, 616 intent.getStringExtra(IccCardConstants.INTENT_KEY_ICC_STATE))); 617 } 618 } else if (action.equals(TelephonyIntents.ACTION_RADIO_TECHNOLOGY_CHANGED)) { 619 String newPhone = intent.getStringExtra(PhoneConstants.PHONE_NAME_KEY); 620 Log.d(LOG_TAG, "Radio technology switched. Now " + newPhone + " is active."); 621 initForNewRadioTechnology(); 622 } else if (action.equals(TelephonyIntents.ACTION_SERVICE_STATE_CHANGED)) { 623 handleServiceStateChanged(intent); 624 } else if (action.equals(TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED)) { 625 int phoneId = intent.getIntExtra(PhoneConstants.PHONE_KEY, 0); 626 phoneInEcm = PhoneFactory.getPhone(phoneId); 627 Log.d(LOG_TAG, "Emergency Callback Mode. phoneId:" + phoneId); 628 if (phoneInEcm != null) { 629 if (TelephonyCapabilities.supportsEcm(phoneInEcm)) { 630 Log.d(LOG_TAG, "Emergency Callback Mode arrived in PhoneApp."); 631 // Start Emergency Callback Mode service 632 if (intent.getBooleanExtra("phoneinECMState", false)) { 633 context.startService(new Intent(context, 634 EmergencyCallbackModeService.class)); 635 } else { 636 phoneInEcm = null; 637 } 638 } else { 639 // It doesn't make sense to get ACTION_EMERGENCY_CALLBACK_MODE_CHANGED 640 // on a device that doesn't support ECM in the first place. 641 Log.e(LOG_TAG, "Got ACTION_EMERGENCY_CALLBACK_MODE_CHANGED, but " 642 + "ECM isn't supported for phone: " + phoneInEcm.getPhoneName()); 643 phoneInEcm = null; 644 } 645 } else { 646 Log.w(LOG_TAG, "phoneInEcm is null."); 647 } 648 } else if (action.equals(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED)) { 649 // Roaming status could be overridden by carrier config, so we need to update it. 650 if (VDBG) Log.v(LOG_TAG, "carrier config changed."); 651 updateDataRoamingStatus(); 652 } else if (action.equals(TelephonyIntents.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED)) { 653 // We also need to pay attention when default data subscription changes. 654 if (VDBG) Log.v(LOG_TAG, "default data sub changed."); 655 mDefaultDataSubId = SubscriptionManager.getDefaultDataSubscriptionId(); 656 registerSettingsObserver(); 657 Phone phone = getPhone(mDefaultDataSubId); 658 if (phone != null) { 659 updateDataRoamingStatus(); 660 } 661 } 662 } 663 } 664 665 private class SipReceiver extends BroadcastReceiver { 666 667 @Override onReceive(Context context, Intent intent)668 public void onReceive(Context context, Intent intent) { 669 String action = intent.getAction(); 670 671 SipAccountRegistry sipAccountRegistry = SipAccountRegistry.getInstance(); 672 if (action.equals(Intent.ACTION_BOOT_COMPLETED)) { 673 SipUtil.startSipService(); 674 } else if (action.equals(SipManager.ACTION_SIP_SERVICE_UP) 675 || action.equals(SipManager.ACTION_SIP_CALL_OPTION_CHANGED)) { 676 sipAccountRegistry.setup(context); 677 } else if (action.equals(SipManager.ACTION_SIP_REMOVE_PHONE)) { 678 if (DBG) { 679 Log.d(LOG_TAG, "SIP_REMOVE_PHONE " 680 + intent.getStringExtra(SipManager.EXTRA_LOCAL_URI)); 681 } 682 sipAccountRegistry.removeSipProfile(intent.getStringExtra( 683 SipManager.EXTRA_LOCAL_URI)); 684 } else { 685 if (DBG) Log.d(LOG_TAG, "onReceive, action not processed: " + action); 686 } 687 } 688 } 689 handleServiceStateChanged(Intent intent)690 private void handleServiceStateChanged(Intent intent) { 691 /** 692 * This used to handle updating EriTextWidgetProvider this routine 693 * and and listening for ACTION_SERVICE_STATE_CHANGED intents could 694 * be removed. But leaving just in case it might be needed in the near 695 * future. 696 */ 697 698 if (VDBG) Log.v(LOG_TAG, "handleServiceStateChanged"); 699 // If service just returned, start sending out the queued messages 700 Bundle extras = intent.getExtras(); 701 if (extras != null) { 702 ServiceState ss = ServiceState.newFromBundle(extras); 703 if (ss != null) { 704 int state = ss.getState(); 705 int subId = intent.getIntExtra(PhoneConstants.SUBSCRIPTION_KEY, 706 SubscriptionManager.INVALID_SUBSCRIPTION_ID); 707 notificationMgr.updateNetworkSelection(state, subId); 708 709 if (VDBG) { 710 Log.v(LOG_TAG, "subId=" + subId + ",mDefaultDataSubId=" 711 + mDefaultDataSubId + ",ss roaming=" + ss.getDataRoaming()); 712 } 713 if (subId == mDefaultDataSubId) { 714 updateDataRoamingStatus(); 715 } 716 } 717 } 718 } 719 720 /** 721 * When roaming, if mobile data cannot be established due to data roaming not enabled, we need 722 * to notify the user so they can enable it through settings. Vise versa if the condition 723 * changes, we need to dismiss the notification. 724 */ updateDataRoamingStatus()725 private void updateDataRoamingStatus() { 726 if (VDBG) Log.v(LOG_TAG, "updateDataRoamingStatus"); 727 Phone phone = getPhone(mDefaultDataSubId); 728 if (phone == null) { 729 Log.w(LOG_TAG, "Can't get phone with sub id = " + mDefaultDataSubId); 730 return; 731 } 732 733 DataConnectionReasons reasons = new DataConnectionReasons(); 734 boolean dataAllowed = phone.isDataAllowed(ApnSetting.TYPE_DEFAULT, reasons); 735 mDataRoamingNotifLog.log("dataAllowed=" + dataAllowed + ", reasons=" + reasons); 736 if (VDBG) Log.v(LOG_TAG, "dataAllowed=" + dataAllowed + ", reasons=" + reasons); 737 if (!mNoDataDueToRoaming 738 && !dataAllowed 739 && reasons.containsOnly(DataDisallowedReasonType.ROAMING_DISABLED)) { 740 // If the only reason of no data is data roaming disabled, then we notify the user 741 // so the user can turn on data roaming. 742 mNoDataDueToRoaming = true; 743 Log.d(LOG_TAG, "Show roaming disconnected notification"); 744 mDataRoamingNotifLog.log("Show"); 745 Message msg = mHandler.obtainMessage(EVENT_DATA_ROAMING_DISCONNECTED); 746 msg.arg1 = mDefaultDataSubId; 747 msg.sendToTarget(); 748 } else if (mNoDataDueToRoaming && (dataAllowed 749 || !reasons.containsOnly(DataDisallowedReasonType.ROAMING_DISABLED))) { 750 // Otherwise dismiss the notification we showed earlier. 751 mNoDataDueToRoaming = false; 752 Log.d(LOG_TAG, "Dismiss roaming disconnected notification"); 753 mDataRoamingNotifLog.log("Hide. data allowed=" + dataAllowed + ", reasons=" + reasons); 754 mHandler.sendEmptyMessage(EVENT_DATA_ROAMING_OK); 755 } 756 } 757 getPhoneInEcm()758 public Phone getPhoneInEcm() { 759 return phoneInEcm; 760 } 761 762 /** 763 * Triggers a refresh of the message waiting (voicemail) indicator. 764 * 765 * @param subId the subscription id we should refresh the notification for. 766 */ refreshMwiIndicator(int subId)767 public void refreshMwiIndicator(int subId) { 768 notificationMgr.refreshMwi(subId); 769 } 770 771 /** 772 * Called when the network selection on the subscription {@code subId} is changed by the user. 773 * 774 * @param subId the subscription id. 775 */ onNetworkSelectionChanged(int subId)776 public void onNetworkSelectionChanged(int subId) { 777 Phone phone = getPhone(subId); 778 if (phone != null) { 779 notificationMgr.updateNetworkSelection(phone.getServiceState().getState(), subId); 780 } else { 781 Log.w(LOG_TAG, "onNetworkSelectionChanged on null phone, subId: " + subId); 782 } 783 } 784 785 /** 786 * Dump the state of the object, add calls to other objects as desired. 787 * 788 * @param fd File descriptor 789 * @param printWriter Print writer 790 * @param args Arguments 791 */ dump(FileDescriptor fd, PrintWriter printWriter, String[] args)792 public void dump(FileDescriptor fd, PrintWriter printWriter, String[] args) { 793 IndentingPrintWriter pw = new IndentingPrintWriter(printWriter, " "); 794 pw.println("------- PhoneGlobals -------"); 795 pw.increaseIndent(); 796 pw.println("mNoDataDueToRoaming=" + mNoDataDueToRoaming); 797 pw.println("mDefaultDataSubId=" + mDefaultDataSubId); 798 pw.println("mDataRoamingNotifLog:"); 799 pw.println("isSmsCapable=" + TelephonyManager.from(this).isSmsCapable()); 800 pw.increaseIndent(); 801 mDataRoamingNotifLog.dump(fd, pw, args); 802 pw.decreaseIndent(); 803 pw.decreaseIndent(); 804 pw.println("------- End PhoneGlobals -------"); 805 } 806 } 807