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.phone.vvm.CarrierVvmPackageInstalledReceiver; 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 CarrierConfigLoader configLoader; 133 134 private CallGatewayManager callGatewayManager; 135 private Phone phoneInEcm; 136 137 static boolean sVoiceCapable = true; 138 139 // TODO: Remove, no longer used. 140 CdmaPhoneCallState cdmaPhoneCallState; 141 142 // The currently-active PUK entry activity and progress dialog. 143 // Normally, these are the Emergency Dialer and the subsequent 144 // progress dialog. null if there is are no such objects in 145 // the foreground. 146 private Activity mPUKEntryActivity; 147 private ProgressDialog mPUKEntryProgressDialog; 148 149 private boolean mDataDisconnectedDueToRoaming = false; 150 151 private WakeState mWakeState = WakeState.SLEEP; 152 153 private PowerManager mPowerManager; 154 private PowerManager.WakeLock mWakeLock; 155 private PowerManager.WakeLock mPartialWakeLock; 156 private KeyguardManager mKeyguardManager; 157 158 private UpdateLock mUpdateLock; 159 160 // Broadcast receiver for various intent broadcasts (see onCreate()) 161 private final BroadcastReceiver mReceiver = new PhoneAppBroadcastReceiver(); 162 163 private final CarrierVvmPackageInstalledReceiver mCarrierVvmPackageInstalledReceiver = 164 new CarrierVvmPackageInstalledReceiver(); 165 166 Handler mHandler = new Handler() { 167 @Override 168 public void handleMessage(Message msg) { 169 PhoneConstants.State phoneState; 170 switch (msg.what) { 171 // TODO: This event should be handled by the lock screen, just 172 // like the "SIM missing" and "Sim locked" cases (bug 1804111). 173 case EVENT_SIM_NETWORK_LOCKED: 174 if (getCarrierConfig().getBoolean( 175 CarrierConfigManager.KEY_IGNORE_SIM_NETWORK_LOCKED_EVENTS_BOOL)) { 176 // Some products don't have the concept of a "SIM network lock" 177 Log.i(LOG_TAG, "Ignoring EVENT_SIM_NETWORK_LOCKED event; " 178 + "not showing 'SIM network unlock' PIN entry screen"); 179 } else { 180 // Normal case: show the "SIM network unlock" PIN entry screen. 181 // The user won't be able to do anything else until 182 // they enter a valid SIM network PIN. 183 Log.i(LOG_TAG, "show sim depersonal panel"); 184 IccNetworkDepersonalizationPanel.showDialog(); 185 } 186 break; 187 188 case EVENT_DATA_ROAMING_DISCONNECTED: 189 notificationMgr.showDataDisconnectedRoaming(); 190 break; 191 192 case EVENT_DATA_ROAMING_OK: 193 notificationMgr.hideDataDisconnectedRoaming(); 194 break; 195 196 case MMI_COMPLETE: 197 onMMIComplete((AsyncResult) msg.obj); 198 break; 199 200 case MMI_CANCEL: 201 PhoneUtils.cancelMmiCode(mCM.getFgPhone()); 202 break; 203 204 case EVENT_SIM_STATE_CHANGED: 205 // Marks the event where the SIM goes into ready state. 206 // Right now, this is only used for the PUK-unlocking 207 // process. 208 if (msg.obj.equals(IccCardConstants.INTENT_VALUE_ICC_READY)) { 209 // when the right event is triggered and there 210 // are UI objects in the foreground, we close 211 // them to display the lock panel. 212 if (mPUKEntryActivity != null) { 213 mPUKEntryActivity.finish(); 214 mPUKEntryActivity = null; 215 } 216 if (mPUKEntryProgressDialog != null) { 217 mPUKEntryProgressDialog.dismiss(); 218 mPUKEntryProgressDialog = null; 219 } 220 } 221 break; 222 223 case EVENT_UNSOL_CDMA_INFO_RECORD: 224 //TODO: handle message here; 225 break; 226 case EVENT_RESTART_SIP: 227 // This should only run if the Phone process crashed and was restarted. We do 228 // not want this running if the device is still in the FBE encrypted state. 229 // This is the same procedure that is triggered in the SipBroadcastReceiver 230 // upon BOOT_COMPLETED. 231 UserManager userManager = UserManager.get(sMe); 232 if (userManager != null && userManager.isUserUnlocked()) { 233 SipUtil.startSipService(); 234 } 235 break; 236 } 237 } 238 }; 239 240 public PhoneGlobals(Context context) { 241 super(context); 242 sMe = this; 243 } 244 245 public void onCreate() { 246 if (VDBG) Log.v(LOG_TAG, "onCreate()..."); 247 248 ContentResolver resolver = getContentResolver(); 249 250 // Cache the "voice capable" flag. 251 // This flag currently comes from a resource (which is 252 // overrideable on a per-product basis): 253 sVoiceCapable = 254 getResources().getBoolean(com.android.internal.R.bool.config_voice_capable); 255 // ...but this might eventually become a PackageManager "system 256 // feature" instead, in which case we'd do something like: 257 // sVoiceCapable = 258 // getPackageManager().hasSystemFeature(PackageManager.FEATURE_TELEPHONY_VOICE_CALLS); 259 260 if (mCM == null) { 261 // Initialize the telephony framework 262 PhoneFactory.makeDefaultPhones(this); 263 264 // Start TelephonyDebugService After the default phone is created. 265 Intent intent = new Intent(this, TelephonyDebugService.class); 266 startService(intent); 267 268 mCM = CallManager.getInstance(); 269 for (Phone phone : PhoneFactory.getPhones()) { 270 mCM.registerPhone(phone); 271 } 272 273 // Create the NotificationMgr singleton, which is used to display 274 // status bar icons and control other status bar behavior. 275 notificationMgr = NotificationMgr.init(this); 276 277 // If PhoneGlobals has crashed and is being restarted, then restart. 278 mHandler.sendEmptyMessage(EVENT_RESTART_SIP); 279 280 // Create an instance of CdmaPhoneCallState and initialize it to IDLE 281 cdmaPhoneCallState = new CdmaPhoneCallState(); 282 cdmaPhoneCallState.CdmaPhoneCallStateInit(); 283 284 // before registering for phone state changes 285 mPowerManager = (PowerManager) getSystemService(Context.POWER_SERVICE); 286 mWakeLock = mPowerManager.newWakeLock(PowerManager.FULL_WAKE_LOCK, LOG_TAG); 287 // lock used to keep the processor awake, when we don't care for the display. 288 mPartialWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK 289 | PowerManager.ON_AFTER_RELEASE, LOG_TAG); 290 291 mKeyguardManager = (KeyguardManager) getSystemService(Context.KEYGUARD_SERVICE); 292 293 // Get UpdateLock to suppress system-update related events (e.g. dialog show-up) 294 // during phone calls. 295 mUpdateLock = new UpdateLock("phone"); 296 297 if (DBG) Log.d(LOG_TAG, "onCreate: mUpdateLock: " + mUpdateLock); 298 299 CallLogger callLogger = new CallLogger(this, new CallLogAsync()); 300 301 callGatewayManager = CallGatewayManager.getInstance(); 302 303 // Create the CallController singleton, which is the interface 304 // to the telephony layer for user-initiated telephony functionality 305 // (like making outgoing calls.) 306 callController = CallController.init(this, callLogger, callGatewayManager); 307 308 // Create the CallerInfoCache singleton, which remembers custom ring tone and 309 // send-to-voicemail settings. 310 // 311 // The asynchronous caching will start just after this call. 312 callerInfoCache = CallerInfoCache.init(this); 313 314 phoneMgr = PhoneInterfaceManager.init(this, PhoneFactory.getDefaultPhone()); 315 316 configLoader = CarrierConfigLoader.init(this); 317 318 // Create the CallNotifer singleton, which handles 319 // asynchronous events from the telephony layer (like 320 // launching the incoming-call UI when an incoming call comes 321 // in.) 322 notifier = CallNotifier.init(this); 323 324 PhoneUtils.registerIccStatus(mHandler, EVENT_SIM_NETWORK_LOCKED); 325 326 // register for MMI/USSD 327 mCM.registerForMmiComplete(mHandler, MMI_COMPLETE, null); 328 329 // register connection tracking to PhoneUtils 330 PhoneUtils.initializeConnectionHandler(mCM); 331 332 // Register for misc other intent broadcasts. 333 IntentFilter intentFilter = 334 new IntentFilter(Intent.ACTION_AIRPLANE_MODE_CHANGED); 335 intentFilter.addAction(TelephonyIntents.ACTION_ANY_DATA_CONNECTION_STATE_CHANGED); 336 intentFilter.addAction(TelephonyIntents.ACTION_SIM_STATE_CHANGED); 337 intentFilter.addAction(TelephonyIntents.ACTION_RADIO_TECHNOLOGY_CHANGED); 338 intentFilter.addAction(TelephonyIntents.ACTION_SERVICE_STATE_CHANGED); 339 intentFilter.addAction(TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED); 340 registerReceiver(mReceiver, intentFilter); 341 342 mCarrierVvmPackageInstalledReceiver.register(this); 343 344 //set the default values for the preferences in the phone. 345 PreferenceManager.setDefaultValues(this, R.xml.network_setting_fragment, false); 346 347 PreferenceManager.setDefaultValues(this, R.xml.call_feature_setting, false); 348 349 // Make sure the audio mode (along with some 350 // audio-mode-related state of our own) is initialized 351 // correctly, given the current state of the phone. 352 PhoneUtils.setAudioMode(mCM); 353 } 354 355 // XXX pre-load the SimProvider so that it's ready 356 resolver.getType(Uri.parse("content://icc/adn")); 357 358 // TODO: Register for Cdma Information Records 359 // phone.registerCdmaInformationRecord(mHandler, EVENT_UNSOL_CDMA_INFO_RECORD, null); 360 361 // Read HAC settings and configure audio hardware 362 if (getResources().getBoolean(R.bool.hac_enabled)) { 363 int hac = android.provider.Settings.System.getInt( 364 getContentResolver(), 365 android.provider.Settings.System.HEARING_AID, 366 0); 367 AudioManager audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE); 368 audioManager.setParameter(SettingsConstants.HAC_KEY, 369 hac == SettingsConstants.HAC_ENABLED 370 ? SettingsConstants.HAC_VAL_ON : SettingsConstants.HAC_VAL_OFF); 371 } 372 } 373 374 /** 375 * Returns the singleton instance of the PhoneApp. 376 */ 377 public static PhoneGlobals getInstance() { 378 if (sMe == null) { 379 throw new IllegalStateException("No PhoneGlobals here!"); 380 } 381 return sMe; 382 } 383 384 /** 385 * Returns the singleton instance of the PhoneApp if running as the 386 * primary user, otherwise null. 387 */ 388 static PhoneGlobals getInstanceIfPrimary() { 389 return sMe; 390 } 391 392 /** 393 * Returns the default phone. 394 * 395 * WARNING: This method should be used carefully, now that there may be multiple phones. 396 */ 397 public static Phone getPhone() { 398 return PhoneFactory.getDefaultPhone(); 399 } 400 401 public static Phone getPhone(int subId) { 402 return PhoneFactory.getPhone(SubscriptionManager.getPhoneId(subId)); 403 } 404 405 /* package */ CallManager getCallManager() { 406 return mCM; 407 } 408 409 public PersistableBundle getCarrierConfig() { 410 return getCarrierConfigForSubId(SubscriptionManager.getDefaultSubscriptionId()); 411 } 412 413 public PersistableBundle getCarrierConfigForSubId(int subId) { 414 return configLoader.getConfigForSubId(subId); 415 } 416 417 /** 418 * Sets the activity responsible for un-PUK-blocking the device 419 * so that we may close it when we receive a positive result. 420 * mPUKEntryActivity is also used to indicate to the device that 421 * we are trying to un-PUK-lock the phone. In other words, iff 422 * it is NOT null, then we are trying to unlock and waiting for 423 * the SIM to move to READY state. 424 * 425 * @param activity is the activity to close when PUK has 426 * finished unlocking. Can be set to null to indicate the unlock 427 * or SIM READYing process is over. 428 */ 429 void setPukEntryActivity(Activity activity) { 430 mPUKEntryActivity = activity; 431 } 432 433 Activity getPUKEntryActivity() { 434 return mPUKEntryActivity; 435 } 436 437 /** 438 * Sets the dialog responsible for notifying the user of un-PUK- 439 * blocking - SIM READYing progress, so that we may dismiss it 440 * when we receive a positive result. 441 * 442 * @param dialog indicates the progress dialog informing the user 443 * of the state of the device. Dismissed upon completion of 444 * READYing process 445 */ 446 void setPukEntryProgressDialog(ProgressDialog dialog) { 447 mPUKEntryProgressDialog = dialog; 448 } 449 450 /** 451 * Controls whether or not the screen is allowed to sleep. 452 * 453 * Once sleep is allowed (WakeState is SLEEP), it will rely on the 454 * settings for the poke lock to determine when to timeout and let 455 * the device sleep {@link PhoneGlobals#setScreenTimeout}. 456 * 457 * @param ws tells the device to how to wake. 458 */ 459 /* package */ void requestWakeState(WakeState ws) { 460 if (VDBG) Log.d(LOG_TAG, "requestWakeState(" + ws + ")..."); 461 synchronized (this) { 462 if (mWakeState != ws) { 463 switch (ws) { 464 case PARTIAL: 465 // acquire the processor wake lock, and release the FULL 466 // lock if it is being held. 467 mPartialWakeLock.acquire(); 468 if (mWakeLock.isHeld()) { 469 mWakeLock.release(); 470 } 471 break; 472 case FULL: 473 // acquire the full wake lock, and release the PARTIAL 474 // lock if it is being held. 475 mWakeLock.acquire(); 476 if (mPartialWakeLock.isHeld()) { 477 mPartialWakeLock.release(); 478 } 479 break; 480 case SLEEP: 481 default: 482 // release both the PARTIAL and FULL locks. 483 if (mWakeLock.isHeld()) { 484 mWakeLock.release(); 485 } 486 if (mPartialWakeLock.isHeld()) { 487 mPartialWakeLock.release(); 488 } 489 break; 490 } 491 mWakeState = ws; 492 } 493 } 494 } 495 496 /** 497 * If we are not currently keeping the screen on, then poke the power 498 * manager to wake up the screen for the user activity timeout duration. 499 */ 500 /* package */ void wakeUpScreen() { 501 synchronized (this) { 502 if (mWakeState == WakeState.SLEEP) { 503 if (DBG) Log.d(LOG_TAG, "pulse screen lock"); 504 mPowerManager.wakeUp(SystemClock.uptimeMillis(), "android.phone:WAKE"); 505 } 506 } 507 } 508 509 /** 510 * Sets the wake state and screen timeout based on the current state 511 * of the phone, and the current state of the in-call UI. 512 * 513 * This method is a "UI Policy" wrapper around 514 * {@link PhoneGlobals#requestWakeState} and {@link PhoneGlobals#setScreenTimeout}. 515 * 516 * It's safe to call this method regardless of the state of the Phone 517 * (e.g. whether or not it's idle), and regardless of the state of the 518 * Phone UI (e.g. whether or not the InCallScreen is active.) 519 */ 520 /* package */ void updateWakeState() { 521 PhoneConstants.State state = mCM.getState(); 522 523 // True if the speakerphone is in use. (If so, we *always* use 524 // the default timeout. Since the user is obviously not holding 525 // the phone up to his/her face, we don't need to worry about 526 // false touches, and thus don't need to turn the screen off so 527 // aggressively.) 528 // Note that we need to make a fresh call to this method any 529 // time the speaker state changes. (That happens in 530 // PhoneUtils.turnOnSpeaker().) 531 boolean isSpeakerInUse = (state == PhoneConstants.State.OFFHOOK) && PhoneUtils.isSpeakerOn(this); 532 533 // TODO (bug 1440854): The screen timeout *might* also need to 534 // depend on the bluetooth state, but this isn't as clear-cut as 535 // the speaker state (since while using BT it's common for the 536 // user to put the phone straight into a pocket, in which case the 537 // timeout should probably still be short.) 538 539 // Decide whether to force the screen on or not. 540 // 541 // Force the screen to be on if the phone is ringing or dialing, 542 // or if we're displaying the "Call ended" UI for a connection in 543 // the "disconnected" state. 544 // However, if the phone is disconnected while the user is in the 545 // middle of selecting a quick response message, we should not force 546 // the screen to be on. 547 // 548 boolean isRinging = (state == PhoneConstants.State.RINGING); 549 boolean isDialing = (mCM.getFgPhone().getForegroundCall().getState() == Call.State.DIALING); 550 boolean keepScreenOn = isRinging || isDialing; 551 // keepScreenOn == true means we'll hold a full wake lock: 552 requestWakeState(keepScreenOn ? WakeState.FULL : WakeState.SLEEP); 553 } 554 555 KeyguardManager getKeyguardManager() { 556 return mKeyguardManager; 557 } 558 559 private void onMMIComplete(AsyncResult r) { 560 if (VDBG) Log.d(LOG_TAG, "onMMIComplete()..."); 561 MmiCode mmiCode = (MmiCode) r.result; 562 PhoneUtils.displayMMIComplete(mmiCode.getPhone(), getInstance(), mmiCode, null, null); 563 } 564 565 private void initForNewRadioTechnology() { 566 if (DBG) Log.d(LOG_TAG, "initForNewRadioTechnology..."); 567 notifier.updateCallNotifierRegistrationsAfterRadioTechnologyChange(); 568 } 569 570 private void handleAirplaneModeChange(Context context, int newMode) { 571 int cellState = Settings.Global.getInt(context.getContentResolver(), 572 Settings.Global.CELL_ON, PhoneConstants.CELL_ON_FLAG); 573 boolean isAirplaneNewlyOn = (newMode == 1); 574 switch (cellState) { 575 case PhoneConstants.CELL_OFF_FLAG: 576 // Airplane mode does not affect the cell radio if user 577 // has turned it off. 578 break; 579 case PhoneConstants.CELL_ON_FLAG: 580 maybeTurnCellOff(context, isAirplaneNewlyOn); 581 break; 582 case PhoneConstants.CELL_OFF_DUE_TO_AIRPLANE_MODE_FLAG: 583 maybeTurnCellOn(context, isAirplaneNewlyOn); 584 break; 585 } 586 } 587 588 /* 589 * Returns true if the radio must be turned off when entering airplane mode. 590 */ 591 private boolean isCellOffInAirplaneMode(Context context) { 592 String airplaneModeRadios = Settings.Global.getString(context.getContentResolver(), 593 Settings.Global.AIRPLANE_MODE_RADIOS); 594 return airplaneModeRadios == null 595 || airplaneModeRadios.contains(Settings.Global.RADIO_CELL); 596 } 597 598 private void setRadioPowerOff(Context context) { 599 Log.i(LOG_TAG, "Turning radio off - airplane"); 600 Settings.Global.putInt(context.getContentResolver(), Settings.Global.CELL_ON, 601 PhoneConstants.CELL_OFF_DUE_TO_AIRPLANE_MODE_FLAG); 602 SystemProperties.set("persist.radio.airplane_mode_on", "1"); 603 Settings.Global.putInt(getContentResolver(), Settings.Global.ENABLE_CELLULAR_ON_BOOT, 0); 604 PhoneUtils.setRadioPower(false); 605 } 606 607 private void setRadioPowerOn(Context context) { 608 Log.i(LOG_TAG, "Turning radio on - airplane"); 609 Settings.Global.putInt(context.getContentResolver(), Settings.Global.CELL_ON, 610 PhoneConstants.CELL_ON_FLAG); 611 Settings.Global.putInt(getContentResolver(), Settings.Global.ENABLE_CELLULAR_ON_BOOT, 612 1); 613 SystemProperties.set("persist.radio.airplane_mode_on", "0"); 614 PhoneUtils.setRadioPower(true); 615 } 616 617 private void maybeTurnCellOff(Context context, boolean isAirplaneNewlyOn) { 618 if (isAirplaneNewlyOn) { 619 // If we are trying to turn off the radio, make sure there are no active 620 // emergency calls. If there are, switch airplane mode back to off. 621 if (PhoneUtils.isInEmergencyCall(mCM)) { 622 // Switch airplane mode back to off. 623 ConnectivityManager.from(this).setAirplaneMode(false); 624 Toast.makeText(this, R.string.radio_off_during_emergency_call, Toast.LENGTH_LONG) 625 .show(); 626 Log.i(LOG_TAG, "Ignoring airplane mode: emergency call. Turning airplane off"); 627 } else if (isCellOffInAirplaneMode(context)) { 628 setRadioPowerOff(context); 629 } else { 630 Log.i(LOG_TAG, "Ignoring airplane mode: settings prevent cell radio power off"); 631 } 632 } 633 } 634 635 private void maybeTurnCellOn(Context context, boolean isAirplaneNewlyOn) { 636 if (!isAirplaneNewlyOn) { 637 setRadioPowerOn(context); 638 } 639 } 640 641 /** 642 * Receiver for misc intent broadcasts the Phone app cares about. 643 */ 644 private class PhoneAppBroadcastReceiver extends BroadcastReceiver { 645 @Override 646 public void onReceive(Context context, Intent intent) { 647 String action = intent.getAction(); 648 if (action.equals(Intent.ACTION_AIRPLANE_MODE_CHANGED)) { 649 int airplaneMode = Settings.Global.getInt(getContentResolver(), 650 Settings.Global.AIRPLANE_MODE_ON, AIRPLANE_OFF); 651 // Treat any non-OFF values as ON. 652 if (airplaneMode != AIRPLANE_OFF) { 653 airplaneMode = AIRPLANE_ON; 654 } 655 handleAirplaneModeChange(context, airplaneMode); 656 } else if (action.equals(TelephonyIntents.ACTION_ANY_DATA_CONNECTION_STATE_CHANGED)) { 657 int subId = intent.getIntExtra(PhoneConstants.SUBSCRIPTION_KEY, 658 SubscriptionManager.INVALID_SUBSCRIPTION_ID); 659 int phoneId = SubscriptionManager.getPhoneId(subId); 660 final String apnType = intent.getStringExtra(PhoneConstants.DATA_APN_TYPE_KEY); 661 final String state = intent.getStringExtra(PhoneConstants.STATE_KEY); 662 final String reason = intent.getStringExtra(PhoneConstants.STATE_CHANGE_REASON_KEY); 663 if (VDBG) { 664 Log.d(LOG_TAG, "mReceiver: ACTION_ANY_DATA_CONNECTION_STATE_CHANGED"); 665 Log.d(LOG_TAG, "- state: " + state); 666 Log.d(LOG_TAG, "- reason: " + reason); 667 Log.d(LOG_TAG, "- subId: " + subId); 668 } 669 Phone phone = SubscriptionManager.isValidPhoneId(phoneId) ? 670 PhoneFactory.getPhone(phoneId) : PhoneFactory.getDefaultPhone(); 671 672 // If the apn type of data connection state changed event is NOT default, 673 // ignore the broadcast intent and avoid action. 674 if (!PhoneConstants.APN_TYPE_DEFAULT.equals(apnType)) { 675 if (VDBG) Log.d(LOG_TAG, "Ignore broadcast intent as not default apn type"); 676 return; 677 } 678 679 // The "data disconnected due to roaming" notification is shown 680 // if (a) you have the "data roaming" feature turned off, and 681 // (b) you just lost data connectivity because you're roaming. 682 // (c) if we haven't shown the notification for this disconnection earlier. 683 if (!mDataDisconnectedDueToRoaming 684 && PhoneConstants.DataState.DISCONNECTED.name().equals(state) 685 && Phone.REASON_ROAMING_ON.equals(reason) 686 && !phone.getDataRoamingEnabled()) { 687 // Notify the user that data call is disconnected due to roaming. Note that 688 // calling this multiple times will not cause multiple notifications. 689 mHandler.sendEmptyMessage(EVENT_DATA_ROAMING_DISCONNECTED); 690 mDataDisconnectedDueToRoaming = true; 691 } else if (mDataDisconnectedDueToRoaming 692 && PhoneConstants.DataState.CONNECTED.name().equals(state)) { 693 // Cancel the notification when data is available. Note it is okay to call this 694 // even if the notification doesn't exist. 695 mHandler.sendEmptyMessage(EVENT_DATA_ROAMING_OK); 696 mDataDisconnectedDueToRoaming = false; 697 } 698 } else if ((action.equals(TelephonyIntents.ACTION_SIM_STATE_CHANGED)) && 699 (mPUKEntryActivity != null)) { 700 // if an attempt to un-PUK-lock the device was made, while we're 701 // receiving this state change notification, notify the handler. 702 // NOTE: This is ONLY triggered if an attempt to un-PUK-lock has 703 // been attempted. 704 mHandler.sendMessage(mHandler.obtainMessage(EVENT_SIM_STATE_CHANGED, 705 intent.getStringExtra(IccCardConstants.INTENT_KEY_ICC_STATE))); 706 } else if (action.equals(TelephonyIntents.ACTION_RADIO_TECHNOLOGY_CHANGED)) { 707 String newPhone = intent.getStringExtra(PhoneConstants.PHONE_NAME_KEY); 708 Log.d(LOG_TAG, "Radio technology switched. Now " + newPhone + " is active."); 709 initForNewRadioTechnology(); 710 } else if (action.equals(TelephonyIntents.ACTION_SERVICE_STATE_CHANGED)) { 711 handleServiceStateChanged(intent); 712 } else if (action.equals(TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED)) { 713 int phoneId = intent.getIntExtra(PhoneConstants.PHONE_KEY, 0); 714 phoneInEcm = PhoneFactory.getPhone(phoneId); 715 Log.d(LOG_TAG, "Emergency Callback Mode. phoneId:" + phoneId); 716 if (phoneInEcm != null) { 717 if (TelephonyCapabilities.supportsEcm(phoneInEcm)) { 718 Log.d(LOG_TAG, "Emergency Callback Mode arrived in PhoneApp."); 719 // Start Emergency Callback Mode service 720 if (intent.getBooleanExtra("phoneinECMState", false)) { 721 context.startService(new Intent(context, 722 EmergencyCallbackModeService.class)); 723 } else { 724 phoneInEcm = null; 725 } 726 } else { 727 // It doesn't make sense to get ACTION_EMERGENCY_CALLBACK_MODE_CHANGED 728 // on a device that doesn't support ECM in the first place. 729 Log.e(LOG_TAG, "Got ACTION_EMERGENCY_CALLBACK_MODE_CHANGED, but " 730 + "ECM isn't supported for phone: " + phoneInEcm.getPhoneName()); 731 phoneInEcm = null; 732 } 733 } else { 734 Log.w(LOG_TAG, "phoneInEcm is null."); 735 } 736 } 737 } 738 } 739 740 private void handleServiceStateChanged(Intent intent) { 741 /** 742 * This used to handle updating EriTextWidgetProvider this routine 743 * and and listening for ACTION_SERVICE_STATE_CHANGED intents could 744 * be removed. But leaving just in case it might be needed in the near 745 * future. 746 */ 747 748 // If service just returned, start sending out the queued messages 749 Bundle extras = intent.getExtras(); 750 if (extras != null) { 751 ServiceState ss = ServiceState.newFromBundle(extras); 752 if (ss != null) { 753 int state = ss.getState(); 754 int subId = intent.getIntExtra(PhoneConstants.SUBSCRIPTION_KEY, 755 SubscriptionManager.INVALID_SUBSCRIPTION_ID); 756 notificationMgr.updateNetworkSelection(state, subId); 757 } 758 } 759 } 760 761 public Phone getPhoneInEcm() { 762 return phoneInEcm; 763 } 764 765 /** 766 * Triggers a refresh of the message waiting (voicemail) indicator. 767 * 768 * @param subId the subscription id we should refresh the notification for. 769 */ 770 public void refreshMwiIndicator(int subId) { 771 notificationMgr.refreshMwi(subId); 772 } 773 774 /** 775 * Dismisses the message waiting (voicemail) indicator. 776 * 777 * @param subId the subscription id we should dismiss the notification for. 778 */ 779 public void clearMwiIndicator(int subId) { 780 // Setting voiceMessageCount to 0 will remove the current notification and clear the system 781 // cached value. 782 Phone phone = getPhone(subId); 783 if (phone == null) { 784 Log.w(LOG_TAG, "clearMwiIndicator on null phone, subId:" + subId); 785 } else { 786 phone.setVoiceMessageCount(0); 787 } 788 } 789 790 /** 791 * Enables or disables the visual voicemail check for message waiting indicator. Default value 792 * is true. MWI is the traditional voicemail notification which should be suppressed if visual 793 * voicemail is active. {@link NotificationMgr#updateMwi(int, boolean, boolean)} currently 794 * checks the {@link android.provider.VoicemailContract.Status#CONFIGURATION_STATE} to suppress 795 * the MWI, but there are several issues. b/31229016 is a bug that when the device boots the 796 * configuration state will be cleared and the MWI for voicemail that arrives when the device 797 * is offline will be cleared, even if the account cannot be activated. A full solution will be 798 * adding a setMwiEnabled() method and stop checking the configuration state, but that is too 799 * risky at this moment. This is a temporary workaround to shut down the configuration state 800 * check if visual voicemail cannot be activated. 801 * <p>TODO(twyen): implement the setMwiEnabled() mentioned above. 802 * 803 * @param subId the account to set the enabled state 804 */ 805 public void setShouldCheckVisualVoicemailConfigurationForMwi(int subId, boolean enabled) { 806 notificationMgr.setShouldCheckVisualVoicemailConfigurationForMwi(subId, enabled); 807 } 808 } 809