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.media.AudioManager; 29 import android.net.ConnectivityManager; 30 import android.net.Uri; 31 import android.os.AsyncResult; 32 import android.os.Bundle; 33 import android.os.Handler; 34 import android.os.Message; 35 import android.os.PersistableBundle; 36 import android.os.PowerManager; 37 import android.os.ServiceManager; 38 import android.os.SystemClock; 39 import android.os.SystemProperties; 40 import android.os.SystemService; 41 import android.os.UpdateLock; 42 import android.os.UserManager; 43 import android.preference.PreferenceManager; 44 import android.provider.Settings; 45 import android.telephony.CarrierConfigManager; 46 import android.telephony.ServiceState; 47 import android.telephony.SubscriptionManager; 48 import android.util.Log; 49 import android.widget.Toast; 50 51 import com.android.internal.telephony.Call; 52 import com.android.internal.telephony.CallManager; 53 import com.android.internal.telephony.IccCardConstants; 54 import com.android.internal.telephony.MmiCode; 55 import com.android.internal.telephony.Phone; 56 import com.android.internal.telephony.PhoneConstants; 57 import com.android.internal.telephony.PhoneFactory; 58 import com.android.internal.telephony.TelephonyCapabilities; 59 import com.android.internal.telephony.TelephonyIntents; 60 import com.android.phone.common.CallLogAsync; 61 import com.android.phone.settings.SettingsConstants; 62 import com.android.server.sip.SipService; 63 import com.android.services.telephony.activation.SimActivationManager; 64 import com.android.services.telephony.sip.SipUtil; 65 66 /** 67 * Global state for the telephony subsystem when running in the primary 68 * phone process. 69 */ 70 public class PhoneGlobals extends ContextWrapper { 71 public static final String LOG_TAG = "PhoneApp"; 72 73 /** 74 * Phone app-wide debug level: 75 * 0 - no debug logging 76 * 1 - normal debug logging if ro.debuggable is set (which is true in 77 * "eng" and "userdebug" builds but not "user" builds) 78 * 2 - ultra-verbose debug logging 79 * 80 * Most individual classes in the phone app have a local DBG constant, 81 * typically set to 82 * (PhoneApp.DBG_LEVEL >= 1) && (SystemProperties.getInt("ro.debuggable", 0) == 1) 83 * or else 84 * (PhoneApp.DBG_LEVEL >= 2) 85 * depending on the desired verbosity. 86 * 87 * ***** DO NOT SUBMIT WITH DBG_LEVEL > 0 ************* 88 */ 89 public static final int DBG_LEVEL = 0; 90 91 private static final boolean DBG = 92 (PhoneGlobals.DBG_LEVEL >= 1) && (SystemProperties.getInt("ro.debuggable", 0) == 1); 93 private static final boolean VDBG = (PhoneGlobals.DBG_LEVEL >= 2); 94 95 // Message codes; see mHandler below. 96 private static final int EVENT_SIM_NETWORK_LOCKED = 3; 97 private static final int EVENT_SIM_STATE_CHANGED = 8; 98 private static final int EVENT_DATA_ROAMING_DISCONNECTED = 10; 99 private static final int EVENT_DATA_ROAMING_OK = 11; 100 private static final int EVENT_UNSOL_CDMA_INFO_RECORD = 12; 101 private static final int EVENT_RESTART_SIP = 13; 102 103 // The MMI codes are also used by the InCallScreen. 104 public static final int MMI_INITIATE = 51; 105 public static final int MMI_COMPLETE = 52; 106 public static final int MMI_CANCEL = 53; 107 // Don't use message codes larger than 99 here; those are reserved for 108 // the individual Activities of the Phone UI. 109 110 public static final int AIRPLANE_ON = 1; 111 public static final int AIRPLANE_OFF = 0; 112 113 /** 114 * Allowable values for the wake lock code. 115 * SLEEP means the device can be put to sleep. 116 * PARTIAL means wake the processor, but we display can be kept off. 117 * FULL means wake both the processor and the display. 118 */ 119 public enum WakeState { 120 SLEEP, 121 PARTIAL, 122 FULL 123 } 124 125 private static PhoneGlobals sMe; 126 127 // A few important fields we expose to the rest of the package 128 // directly (rather than thru set/get methods) for efficiency. 129 CallController callController; 130 CallManager mCM; 131 CallNotifier notifier; 132 CallerInfoCache callerInfoCache; 133 NotificationMgr notificationMgr; 134 public PhoneInterfaceManager phoneMgr; 135 public SimActivationManager simActivationManager; 136 CarrierConfigLoader configLoader; 137 138 private CallGatewayManager callGatewayManager; 139 private Phone phoneInEcm; 140 141 static boolean sVoiceCapable = true; 142 143 // TODO: Remove, no longer used. 144 CdmaPhoneCallState cdmaPhoneCallState; 145 146 // The currently-active PUK entry activity and progress dialog. 147 // Normally, these are the Emergency Dialer and the subsequent 148 // progress dialog. null if there is are no such objects in 149 // the foreground. 150 private Activity mPUKEntryActivity; 151 private ProgressDialog mPUKEntryProgressDialog; 152 153 private boolean mDataDisconnectedDueToRoaming = false; 154 155 private WakeState mWakeState = WakeState.SLEEP; 156 157 private PowerManager mPowerManager; 158 private PowerManager.WakeLock mWakeLock; 159 private PowerManager.WakeLock mPartialWakeLock; 160 private KeyguardManager mKeyguardManager; 161 162 private UpdateLock mUpdateLock; 163 164 // Broadcast receiver for various intent broadcasts (see onCreate()) 165 private final BroadcastReceiver mReceiver = new PhoneAppBroadcastReceiver(); 166 167 /** 168 * The singleton OtaUtils instance used for OTASP calls. 169 * 170 * The OtaUtils instance is created lazily the first time we need to 171 * make an OTASP call, regardless of whether it's an interactive or 172 * non-interactive OTASP call. 173 */ 174 public OtaUtils otaUtils; 175 176 // Following are the CDMA OTA information Objects used during OTA Call. 177 // cdmaOtaProvisionData object store static OTA information that needs 178 // to be maintained even during Slider open/close scenarios. 179 // cdmaOtaConfigData object stores configuration info to control visiblity 180 // of each OTA Screens. 181 // cdmaOtaScreenState object store OTA Screen State information. 182 public OtaUtils.CdmaOtaProvisionData cdmaOtaProvisionData; 183 public OtaUtils.CdmaOtaConfigData cdmaOtaConfigData; 184 public OtaUtils.CdmaOtaScreenState cdmaOtaScreenState; 185 public OtaUtils.CdmaOtaInCallScreenUiState cdmaOtaInCallScreenUiState; 186 187 Handler mHandler = new Handler() { 188 @Override 189 public void handleMessage(Message msg) { 190 PhoneConstants.State phoneState; 191 switch (msg.what) { 192 // TODO: This event should be handled by the lock screen, just 193 // like the "SIM missing" and "Sim locked" cases (bug 1804111). 194 case EVENT_SIM_NETWORK_LOCKED: 195 if (getCarrierConfig().getBoolean( 196 CarrierConfigManager.KEY_IGNORE_SIM_NETWORK_LOCKED_EVENTS_BOOL)) { 197 // Some products don't have the concept of a "SIM network lock" 198 Log.i(LOG_TAG, "Ignoring EVENT_SIM_NETWORK_LOCKED event; " 199 + "not showing 'SIM network unlock' PIN entry screen"); 200 } else { 201 // Normal case: show the "SIM network unlock" PIN entry screen. 202 // The user won't be able to do anything else until 203 // they enter a valid SIM network PIN. 204 Log.i(LOG_TAG, "show sim depersonal panel"); 205 IccNetworkDepersonalizationPanel.showDialog(); 206 } 207 break; 208 209 case EVENT_DATA_ROAMING_DISCONNECTED: 210 notificationMgr.showDataDisconnectedRoaming(); 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 // when the right event is triggered and there 231 // are UI objects in the foreground, we close 232 // them to display the lock panel. 233 if (mPUKEntryActivity != null) { 234 mPUKEntryActivity.finish(); 235 mPUKEntryActivity = null; 236 } 237 if (mPUKEntryProgressDialog != null) { 238 mPUKEntryProgressDialog.dismiss(); 239 mPUKEntryProgressDialog = null; 240 } 241 } 242 break; 243 244 case EVENT_UNSOL_CDMA_INFO_RECORD: 245 //TODO: handle message here; 246 break; 247 case EVENT_RESTART_SIP: 248 // This should only run if the Phone process crashed and was restarted. We do 249 // not want this running if the device is still in the FBE encrypted state. 250 // This is the same procedure that is triggered in the SipBroadcastReceiver 251 // upon BOOT_COMPLETED. 252 UserManager userManager = UserManager.get(sMe); 253 if (userManager != null && userManager.isUserUnlocked()) { 254 SipUtil.startSipService(); 255 } 256 break; 257 } 258 } 259 }; 260 261 public PhoneGlobals(Context context) { 262 super(context); 263 sMe = this; 264 } 265 266 public void onCreate() { 267 if (VDBG) Log.v(LOG_TAG, "onCreate()..."); 268 269 ContentResolver resolver = getContentResolver(); 270 271 // Cache the "voice capable" flag. 272 // This flag currently comes from a resource (which is 273 // overrideable on a per-product basis): 274 sVoiceCapable = 275 getResources().getBoolean(com.android.internal.R.bool.config_voice_capable); 276 // ...but this might eventually become a PackageManager "system 277 // feature" instead, in which case we'd do something like: 278 // sVoiceCapable = 279 // getPackageManager().hasSystemFeature(PackageManager.FEATURE_TELEPHONY_VOICE_CALLS); 280 281 if (mCM == null) { 282 // Initialize the telephony framework 283 PhoneFactory.makeDefaultPhones(this); 284 285 // Start TelephonyDebugService After the default phone is created. 286 Intent intent = new Intent(this, TelephonyDebugService.class); 287 startService(intent); 288 289 mCM = CallManager.getInstance(); 290 for (Phone phone : PhoneFactory.getPhones()) { 291 mCM.registerPhone(phone); 292 } 293 294 // Create the NotificationMgr singleton, which is used to display 295 // status bar icons and control other status bar behavior. 296 notificationMgr = NotificationMgr.init(this); 297 298 // If PhoneGlobals has crashed and is being restarted, then restart. 299 mHandler.sendEmptyMessage(EVENT_RESTART_SIP); 300 301 // Create an instance of CdmaPhoneCallState and initialize it to IDLE 302 cdmaPhoneCallState = new CdmaPhoneCallState(); 303 cdmaPhoneCallState.CdmaPhoneCallStateInit(); 304 305 // before registering for phone state changes 306 mPowerManager = (PowerManager) getSystemService(Context.POWER_SERVICE); 307 mWakeLock = mPowerManager.newWakeLock(PowerManager.FULL_WAKE_LOCK, LOG_TAG); 308 // lock used to keep the processor awake, when we don't care for the display. 309 mPartialWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK 310 | PowerManager.ON_AFTER_RELEASE, LOG_TAG); 311 312 mKeyguardManager = (KeyguardManager) getSystemService(Context.KEYGUARD_SERVICE); 313 314 // Get UpdateLock to suppress system-update related events (e.g. dialog show-up) 315 // during phone calls. 316 mUpdateLock = new UpdateLock("phone"); 317 318 if (DBG) Log.d(LOG_TAG, "onCreate: mUpdateLock: " + mUpdateLock); 319 320 CallLogger callLogger = new CallLogger(this, new CallLogAsync()); 321 322 callGatewayManager = CallGatewayManager.getInstance(); 323 324 // Create the CallController singleton, which is the interface 325 // to the telephony layer for user-initiated telephony functionality 326 // (like making outgoing calls.) 327 callController = CallController.init(this, callLogger, callGatewayManager); 328 329 // Create the CallerInfoCache singleton, which remembers custom ring tone and 330 // send-to-voicemail settings. 331 // 332 // The asynchronous caching will start just after this call. 333 callerInfoCache = CallerInfoCache.init(this); 334 335 phoneMgr = PhoneInterfaceManager.init(this, PhoneFactory.getDefaultPhone()); 336 337 configLoader = CarrierConfigLoader.init(this); 338 339 // Create the CallNotifer singleton, which handles 340 // asynchronous events from the telephony layer (like 341 // launching the incoming-call UI when an incoming call comes 342 // in.) 343 notifier = CallNotifier.init(this); 344 345 PhoneUtils.registerIccStatus(mHandler, EVENT_SIM_NETWORK_LOCKED); 346 347 // register for MMI/USSD 348 mCM.registerForMmiComplete(mHandler, MMI_COMPLETE, null); 349 350 // register connection tracking to PhoneUtils 351 PhoneUtils.initializeConnectionHandler(mCM); 352 353 // Register for misc other intent broadcasts. 354 IntentFilter intentFilter = 355 new IntentFilter(Intent.ACTION_AIRPLANE_MODE_CHANGED); 356 intentFilter.addAction(TelephonyIntents.ACTION_ANY_DATA_CONNECTION_STATE_CHANGED); 357 intentFilter.addAction(TelephonyIntents.ACTION_SIM_STATE_CHANGED); 358 intentFilter.addAction(TelephonyIntents.ACTION_RADIO_TECHNOLOGY_CHANGED); 359 intentFilter.addAction(TelephonyIntents.ACTION_SERVICE_STATE_CHANGED); 360 intentFilter.addAction(TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED); 361 registerReceiver(mReceiver, intentFilter); 362 363 //set the default values for the preferences in the phone. 364 PreferenceManager.setDefaultValues(this, R.xml.network_setting, false); 365 366 PreferenceManager.setDefaultValues(this, R.xml.call_feature_setting, false); 367 368 // Make sure the audio mode (along with some 369 // audio-mode-related state of our own) is initialized 370 // correctly, given the current state of the phone. 371 PhoneUtils.setAudioMode(mCM); 372 } 373 374 cdmaOtaProvisionData = new OtaUtils.CdmaOtaProvisionData(); 375 cdmaOtaConfigData = new OtaUtils.CdmaOtaConfigData(); 376 cdmaOtaScreenState = new OtaUtils.CdmaOtaScreenState(); 377 cdmaOtaInCallScreenUiState = new OtaUtils.CdmaOtaInCallScreenUiState(); 378 379 simActivationManager = new SimActivationManager(); 380 381 // XXX pre-load the SimProvider so that it's ready 382 resolver.getType(Uri.parse("content://icc/adn")); 383 384 // TODO: Register for Cdma Information Records 385 // phone.registerCdmaInformationRecord(mHandler, EVENT_UNSOL_CDMA_INFO_RECORD, null); 386 387 // Read HAC settings and configure audio hardware 388 if (getResources().getBoolean(R.bool.hac_enabled)) { 389 int hac = android.provider.Settings.System.getInt( 390 getContentResolver(), 391 android.provider.Settings.System.HEARING_AID, 392 0); 393 AudioManager audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE); 394 audioManager.setParameter(SettingsConstants.HAC_KEY, 395 hac == SettingsConstants.HAC_ENABLED 396 ? SettingsConstants.HAC_VAL_ON : SettingsConstants.HAC_VAL_OFF); 397 } 398 } 399 400 /** 401 * Returns the singleton instance of the PhoneApp. 402 */ 403 public static PhoneGlobals getInstance() { 404 if (sMe == null) { 405 throw new IllegalStateException("No PhoneGlobals here!"); 406 } 407 return sMe; 408 } 409 410 /** 411 * Returns the singleton instance of the PhoneApp if running as the 412 * primary user, otherwise null. 413 */ 414 static PhoneGlobals getInstanceIfPrimary() { 415 return sMe; 416 } 417 418 /** 419 * Returns the default phone. 420 * 421 * WARNING: This method should be used carefully, now that there may be multiple phones. 422 */ 423 public static Phone getPhone() { 424 return PhoneFactory.getDefaultPhone(); 425 } 426 427 public static Phone getPhone(int subId) { 428 return PhoneFactory.getPhone(SubscriptionManager.getPhoneId(subId)); 429 } 430 431 /* package */ CallManager getCallManager() { 432 return mCM; 433 } 434 435 public PersistableBundle getCarrierConfig() { 436 return getCarrierConfigForSubId(SubscriptionManager.getDefaultSubscriptionId()); 437 } 438 439 public PersistableBundle getCarrierConfigForSubId(int subId) { 440 return configLoader.getConfigForSubId(subId); 441 } 442 443 /** 444 * Handles OTASP-related events from the telephony layer. 445 * 446 * While an OTASP call is active, the CallNotifier forwards 447 * OTASP-related telephony events to this method. 448 */ 449 void handleOtaspEvent(Message msg) { 450 if (DBG) Log.d(LOG_TAG, "handleOtaspEvent(message " + msg + ")..."); 451 452 if (otaUtils == null) { 453 // We shouldn't be getting OTASP events without ever 454 // having started the OTASP call in the first place! 455 Log.w(LOG_TAG, "handleOtaEvents: got an event but otaUtils is null! " 456 + "message = " + msg); 457 return; 458 } 459 460 otaUtils.onOtaProvisionStatusChanged((AsyncResult) msg.obj); 461 } 462 463 /** 464 * Similarly, handle the disconnect event of an OTASP call 465 * by forwarding it to the OtaUtils instance. 466 */ 467 /* package */ void handleOtaspDisconnect() { 468 if (DBG) Log.d(LOG_TAG, "handleOtaspDisconnect()..."); 469 470 if (otaUtils == null) { 471 // We shouldn't be getting OTASP events without ever 472 // having started the OTASP call in the first place! 473 Log.w(LOG_TAG, "handleOtaspDisconnect: otaUtils is null!"); 474 return; 475 } 476 477 otaUtils.onOtaspDisconnect(); 478 } 479 480 /** 481 * Sets the activity responsible for un-PUK-blocking the device 482 * so that we may close it when we receive a positive result. 483 * mPUKEntryActivity is also used to indicate to the device that 484 * we are trying to un-PUK-lock the phone. In other words, iff 485 * it is NOT null, then we are trying to unlock and waiting for 486 * the SIM to move to READY state. 487 * 488 * @param activity is the activity to close when PUK has 489 * finished unlocking. Can be set to null to indicate the unlock 490 * or SIM READYing process is over. 491 */ 492 void setPukEntryActivity(Activity activity) { 493 mPUKEntryActivity = activity; 494 } 495 496 Activity getPUKEntryActivity() { 497 return mPUKEntryActivity; 498 } 499 500 /** 501 * Sets the dialog responsible for notifying the user of un-PUK- 502 * blocking - SIM READYing progress, so that we may dismiss it 503 * when we receive a positive result. 504 * 505 * @param dialog indicates the progress dialog informing the user 506 * of the state of the device. Dismissed upon completion of 507 * READYing process 508 */ 509 void setPukEntryProgressDialog(ProgressDialog dialog) { 510 mPUKEntryProgressDialog = dialog; 511 } 512 513 /** 514 * Controls whether or not the screen is allowed to sleep. 515 * 516 * Once sleep is allowed (WakeState is SLEEP), it will rely on the 517 * settings for the poke lock to determine when to timeout and let 518 * the device sleep {@link PhoneGlobals#setScreenTimeout}. 519 * 520 * @param ws tells the device to how to wake. 521 */ 522 /* package */ void requestWakeState(WakeState ws) { 523 if (VDBG) Log.d(LOG_TAG, "requestWakeState(" + ws + ")..."); 524 synchronized (this) { 525 if (mWakeState != ws) { 526 switch (ws) { 527 case PARTIAL: 528 // acquire the processor wake lock, and release the FULL 529 // lock if it is being held. 530 mPartialWakeLock.acquire(); 531 if (mWakeLock.isHeld()) { 532 mWakeLock.release(); 533 } 534 break; 535 case FULL: 536 // acquire the full wake lock, and release the PARTIAL 537 // lock if it is being held. 538 mWakeLock.acquire(); 539 if (mPartialWakeLock.isHeld()) { 540 mPartialWakeLock.release(); 541 } 542 break; 543 case SLEEP: 544 default: 545 // release both the PARTIAL and FULL locks. 546 if (mWakeLock.isHeld()) { 547 mWakeLock.release(); 548 } 549 if (mPartialWakeLock.isHeld()) { 550 mPartialWakeLock.release(); 551 } 552 break; 553 } 554 mWakeState = ws; 555 } 556 } 557 } 558 559 /** 560 * If we are not currently keeping the screen on, then poke the power 561 * manager to wake up the screen for the user activity timeout duration. 562 */ 563 /* package */ void wakeUpScreen() { 564 synchronized (this) { 565 if (mWakeState == WakeState.SLEEP) { 566 if (DBG) Log.d(LOG_TAG, "pulse screen lock"); 567 mPowerManager.wakeUp(SystemClock.uptimeMillis(), "android.phone:WAKE"); 568 } 569 } 570 } 571 572 /** 573 * Sets the wake state and screen timeout based on the current state 574 * of the phone, and the current state of the in-call UI. 575 * 576 * This method is a "UI Policy" wrapper around 577 * {@link PhoneGlobals#requestWakeState} and {@link PhoneGlobals#setScreenTimeout}. 578 * 579 * It's safe to call this method regardless of the state of the Phone 580 * (e.g. whether or not it's idle), and regardless of the state of the 581 * Phone UI (e.g. whether or not the InCallScreen is active.) 582 */ 583 /* package */ void updateWakeState() { 584 PhoneConstants.State state = mCM.getState(); 585 586 // True if the speakerphone is in use. (If so, we *always* use 587 // the default timeout. Since the user is obviously not holding 588 // the phone up to his/her face, we don't need to worry about 589 // false touches, and thus don't need to turn the screen off so 590 // aggressively.) 591 // Note that we need to make a fresh call to this method any 592 // time the speaker state changes. (That happens in 593 // PhoneUtils.turnOnSpeaker().) 594 boolean isSpeakerInUse = (state == PhoneConstants.State.OFFHOOK) && PhoneUtils.isSpeakerOn(this); 595 596 // TODO (bug 1440854): The screen timeout *might* also need to 597 // depend on the bluetooth state, but this isn't as clear-cut as 598 // the speaker state (since while using BT it's common for the 599 // user to put the phone straight into a pocket, in which case the 600 // timeout should probably still be short.) 601 602 // Decide whether to force the screen on or not. 603 // 604 // Force the screen to be on if the phone is ringing or dialing, 605 // or if we're displaying the "Call ended" UI for a connection in 606 // the "disconnected" state. 607 // However, if the phone is disconnected while the user is in the 608 // middle of selecting a quick response message, we should not force 609 // the screen to be on. 610 // 611 boolean isRinging = (state == PhoneConstants.State.RINGING); 612 boolean isDialing = (mCM.getFgPhone().getForegroundCall().getState() == Call.State.DIALING); 613 boolean keepScreenOn = isRinging || isDialing; 614 // keepScreenOn == true means we'll hold a full wake lock: 615 requestWakeState(keepScreenOn ? WakeState.FULL : WakeState.SLEEP); 616 } 617 618 KeyguardManager getKeyguardManager() { 619 return mKeyguardManager; 620 } 621 622 private void onMMIComplete(AsyncResult r) { 623 if (VDBG) Log.d(LOG_TAG, "onMMIComplete()..."); 624 MmiCode mmiCode = (MmiCode) r.result; 625 PhoneUtils.displayMMIComplete(mmiCode.getPhone(), getInstance(), mmiCode, null, null); 626 } 627 628 private void initForNewRadioTechnology(int phoneId) { 629 if (DBG) Log.d(LOG_TAG, "initForNewRadioTechnology..."); 630 631 final Phone phone = PhoneFactory.getPhone(phoneId); 632 if (phone == null || !TelephonyCapabilities.supportsOtasp(phone)) { 633 // Clean up OTA for non-CDMA since it is only valid for CDMA. 634 clearOtaState(); 635 } 636 637 notifier.updateCallNotifierRegistrationsAfterRadioTechnologyChange(); 638 } 639 640 private void handleAirplaneModeChange(int newMode) { 641 if (newMode == AIRPLANE_ON) { 642 // If we are trying to turn off the radio, make sure there are no active 643 // emergency calls. If there are, switch airplane mode back to off. 644 if (PhoneUtils.isInEmergencyCall(mCM)) { 645 // Switch airplane mode back to off. 646 ConnectivityManager.from(this).setAirplaneMode(false); 647 Toast.makeText(this, R.string.radio_off_during_emergency_call, Toast.LENGTH_LONG) 648 .show(); 649 Log.i(LOG_TAG, "Ignoring airplane mode: emergency call. Turning airplane off"); 650 } else { 651 Log.i(LOG_TAG, "Turning radio off - airplane"); 652 PhoneUtils.setRadioPower(false); 653 } 654 } else { 655 Log.i(LOG_TAG, "Turning radio on - airplane"); 656 PhoneUtils.setRadioPower(true); 657 } 658 } 659 660 /** 661 * Receiver for misc intent broadcasts the Phone app cares about. 662 */ 663 private class PhoneAppBroadcastReceiver extends BroadcastReceiver { 664 @Override 665 public void onReceive(Context context, Intent intent) { 666 String action = intent.getAction(); 667 if (action.equals(Intent.ACTION_AIRPLANE_MODE_CHANGED)) { 668 int airplaneMode = Settings.Global.getInt(getContentResolver(), 669 Settings.Global.AIRPLANE_MODE_ON, AIRPLANE_OFF); 670 // Treat any non-OFF values as ON. 671 if (airplaneMode != AIRPLANE_OFF) { 672 airplaneMode = AIRPLANE_ON; 673 } 674 handleAirplaneModeChange(airplaneMode); 675 } else if (action.equals(TelephonyIntents.ACTION_ANY_DATA_CONNECTION_STATE_CHANGED)) { 676 int subId = intent.getIntExtra(PhoneConstants.SUBSCRIPTION_KEY, 677 SubscriptionManager.INVALID_SUBSCRIPTION_ID); 678 int phoneId = SubscriptionManager.getPhoneId(subId); 679 String state = intent.getStringExtra(PhoneConstants.STATE_KEY); 680 if (VDBG) { 681 Log.d(LOG_TAG, "mReceiver: ACTION_ANY_DATA_CONNECTION_STATE_CHANGED"); 682 Log.d(LOG_TAG, "- state: " + state); 683 Log.d(LOG_TAG, "- reason: " 684 + intent.getStringExtra(PhoneConstants.STATE_CHANGE_REASON_KEY)); 685 Log.d(LOG_TAG, "- subId: " + subId); 686 Log.d(LOG_TAG, "- phoneId: " + phoneId); 687 } 688 Phone phone = SubscriptionManager.isValidPhoneId(phoneId) ? 689 PhoneFactory.getPhone(phoneId) : PhoneFactory.getDefaultPhone(); 690 691 // The "data disconnected due to roaming" notification is shown 692 // if (a) you have the "data roaming" feature turned off, and 693 // (b) you just lost data connectivity because you're roaming. 694 boolean disconnectedDueToRoaming = 695 !phone.getDataRoamingEnabled() 696 && PhoneConstants.DataState.DISCONNECTED.equals(state) 697 && Phone.REASON_ROAMING_ON.equals( 698 intent.getStringExtra(PhoneConstants.STATE_CHANGE_REASON_KEY)); 699 if (mDataDisconnectedDueToRoaming != disconnectedDueToRoaming) { 700 mDataDisconnectedDueToRoaming = disconnectedDueToRoaming; 701 mHandler.sendEmptyMessage(disconnectedDueToRoaming 702 ? EVENT_DATA_ROAMING_DISCONNECTED : EVENT_DATA_ROAMING_OK); 703 } 704 } else if ((action.equals(TelephonyIntents.ACTION_SIM_STATE_CHANGED)) && 705 (mPUKEntryActivity != null)) { 706 // if an attempt to un-PUK-lock the device was made, while we're 707 // receiving this state change notification, notify the handler. 708 // NOTE: This is ONLY triggered if an attempt to un-PUK-lock has 709 // been attempted. 710 mHandler.sendMessage(mHandler.obtainMessage(EVENT_SIM_STATE_CHANGED, 711 intent.getStringExtra(IccCardConstants.INTENT_KEY_ICC_STATE))); 712 } else if (action.equals(TelephonyIntents.ACTION_RADIO_TECHNOLOGY_CHANGED)) { 713 String newPhone = intent.getStringExtra(PhoneConstants.PHONE_NAME_KEY); 714 int phoneId = intent.getIntExtra(PhoneConstants.PHONE_KEY, 715 SubscriptionManager.INVALID_PHONE_INDEX); 716 Log.d(LOG_TAG, "Radio technology switched. Now " + newPhone + " (" + phoneId 717 + ") is active."); 718 initForNewRadioTechnology(phoneId); 719 } else if (action.equals(TelephonyIntents.ACTION_SERVICE_STATE_CHANGED)) { 720 handleServiceStateChanged(intent); 721 } else if (action.equals(TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED)) { 722 int phoneId = intent.getIntExtra(PhoneConstants.PHONE_KEY, 0); 723 phoneInEcm = getPhone(phoneId); 724 Log.d(LOG_TAG, "Emergency Callback Mode. phoneId:" + phoneId); 725 if (phoneInEcm != null) { 726 if (TelephonyCapabilities.supportsEcm(phoneInEcm)) { 727 Log.d(LOG_TAG, "Emergency Callback Mode arrived in PhoneApp."); 728 // Start Emergency Callback Mode service 729 if (intent.getBooleanExtra("phoneinECMState", false)) { 730 context.startService(new Intent(context, 731 EmergencyCallbackModeService.class)); 732 } else { 733 phoneInEcm = null; 734 } 735 } else { 736 // It doesn't make sense to get ACTION_EMERGENCY_CALLBACK_MODE_CHANGED 737 // on a device that doesn't support ECM in the first place. 738 Log.e(LOG_TAG, "Got ACTION_EMERGENCY_CALLBACK_MODE_CHANGED, but " 739 + "ECM isn't supported for phone: " + phoneInEcm.getPhoneName()); 740 phoneInEcm = null; 741 } 742 } else { 743 Log.w(LOG_TAG, "phoneInEcm is null."); 744 } 745 } 746 } 747 } 748 749 private void handleServiceStateChanged(Intent intent) { 750 /** 751 * This used to handle updating EriTextWidgetProvider this routine 752 * and and listening for ACTION_SERVICE_STATE_CHANGED intents could 753 * be removed. But leaving just in case it might be needed in the near 754 * future. 755 */ 756 757 // If service just returned, start sending out the queued messages 758 Bundle extras = intent.getExtras(); 759 if (extras != null) { 760 ServiceState ss = ServiceState.newFromBundle(extras); 761 if (ss != null) { 762 int state = ss.getState(); 763 notificationMgr.updateNetworkSelection(state); 764 } 765 } 766 } 767 768 // it is safe to call clearOtaState() even if the InCallScreen isn't active 769 public void clearOtaState() { 770 if (DBG) Log.d(LOG_TAG, "- clearOtaState ..."); 771 if (otaUtils != null) { 772 otaUtils.cleanOtaScreen(true); 773 if (DBG) Log.d(LOG_TAG, " - clearOtaState clears OTA screen"); 774 } 775 } 776 777 // it is safe to call dismissOtaDialogs() even if the InCallScreen isn't active 778 public void dismissOtaDialogs() { 779 if (DBG) Log.d(LOG_TAG, "- dismissOtaDialogs ..."); 780 if (otaUtils != null) { 781 otaUtils.dismissAllOtaDialogs(); 782 if (DBG) Log.d(LOG_TAG, " - dismissOtaDialogs clears OTA dialogs"); 783 } 784 } 785 786 public Phone getPhoneInEcm() { 787 return phoneInEcm; 788 } 789 790 /** 791 * Triggers a refresh of the message waiting (voicemail) indicator. 792 * 793 * @param subId the subscription id we should refresh the notification for. 794 */ 795 public void refreshMwiIndicator(int subId) { 796 notificationMgr.refreshMwi(subId); 797 } 798 799 /** 800 * Dismisses the message waiting (voicemail) indicator. 801 * 802 * @param subId the subscription id we should dismiss the notification for. 803 */ 804 public void clearMwiIndicator(int subId) { 805 notificationMgr.updateMwi(subId, false); 806 } 807 } 808