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