PhoneApp.java revision f6eb7893215a875863e1e0200e4aa3174137f76c
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 17package com.android.phone; 18 19import android.app.Activity; 20import android.app.Application; 21import android.app.KeyguardManager; 22import android.app.ProgressDialog; 23import android.bluetooth.BluetoothHeadset; 24import android.content.BroadcastReceiver; 25import android.content.ContentResolver; 26import android.content.Context; 27import android.content.Intent; 28import android.content.IntentFilter; 29import android.content.res.Configuration; 30import android.media.AudioManager; 31import android.net.Uri; 32import android.os.AsyncResult; 33import android.os.Binder; 34import android.os.Handler; 35import android.os.IBinder; 36import android.os.IPowerManager; 37import android.os.LocalPowerManager; 38import android.os.Message; 39import android.os.PowerManager; 40import android.os.RemoteException; 41import android.os.ServiceManager; 42import android.os.SystemClock; 43import android.os.SystemProperties; 44import android.preference.PreferenceManager; 45import android.provider.Settings.System; 46import android.telephony.ServiceState; 47import android.util.Config; 48import android.util.Log; 49import android.view.KeyEvent; 50import android.widget.Toast; 51 52import com.android.internal.telephony.Call; 53import com.android.internal.telephony.IccCard; 54import com.android.internal.telephony.MmiCode; 55import com.android.internal.telephony.Phone; 56import com.android.internal.telephony.PhoneFactory; 57import com.android.internal.telephony.TelephonyIntents; 58import com.android.internal.telephony.cdma.EriInfo; 59import com.android.phone.OtaUtils.CdmaOtaScreenState; 60 61/** 62 * Top-level Application class for the Phone app. 63 */ 64public class PhoneApp extends Application { 65 /* package */ static final String LOG_TAG = "PhoneApp"; 66 67 /** 68 * Phone app-wide debug level: 69 * 0 - no debug logging 70 * 1 - normal debug logging if ro.debuggable is set (which is true in 71 * "eng" and "userdebug" builds but not "user" builds) 72 * 2 - ultra-verbose debug logging 73 * 74 * Most individual classes in the phone app have a local DBG constant, 75 * typically set to 76 * (PhoneApp.DBG_LEVEL >= 1) && (SystemProperties.getInt("ro.debuggable", 0) == 1) 77 * or else 78 * (PhoneApp.DBG_LEVEL >= 2) 79 * depending on the desired verbosity. 80 */ 81 /* package */ static final int DBG_LEVEL = 1; 82 83 private static final boolean DBG = 84 (PhoneApp.DBG_LEVEL >= 1) && (SystemProperties.getInt("ro.debuggable", 0) == 1); 85 private static final boolean VDBG = (PhoneApp.DBG_LEVEL >= 2); 86 87 // Message codes; see mHandler below. 88 private static final int EVENT_SIM_ABSENT = 1; 89 private static final int EVENT_SIM_LOCKED = 2; 90 private static final int EVENT_SIM_NETWORK_LOCKED = 3; 91 private static final int EVENT_WIRED_HEADSET_PLUG = 7; 92 private static final int EVENT_SIM_STATE_CHANGED = 8; 93 private static final int EVENT_UPDATE_INCALL_NOTIFICATION = 9; 94 private static final int EVENT_DATA_ROAMING_DISCONNECTED = 10; 95 private static final int EVENT_DATA_ROAMING_OK = 11; 96 private static final int EVENT_UNSOL_CDMA_INFO_RECORD = 12; 97 98 // The MMI codes are also used by the InCallScreen. 99 public static final int MMI_INITIATE = 51; 100 public static final int MMI_COMPLETE = 52; 101 public static final int MMI_CANCEL = 53; 102 // Don't use message codes larger than 99 here; those are reserved for 103 // the individual Activities of the Phone UI. 104 105 /** 106 * Allowable values for the poke lock code (timeout between a user activity and the 107 * going to sleep), please refer to {@link com.android.server.PowerManagerService} 108 * for additional reference. 109 * SHORT uses the short delay for the timeout (SHORT_KEYLIGHT_DELAY, 6 sec) 110 * MEDIUM uses the medium delay for the timeout (MEDIUM_KEYLIGHT_DELAY, 15 sec) 111 * DEFAULT is the system-wide default delay for the timeout (1 min) 112 */ 113 public enum ScreenTimeoutDuration { 114 SHORT, 115 MEDIUM, 116 DEFAULT 117 } 118 119 /** 120 * Allowable values for the wake lock code. 121 * SLEEP means the device can be put to sleep. 122 * PARTIAL means wake the processor, but we display can be kept off. 123 * FULL means wake both the processor and the display. 124 */ 125 public enum WakeState { 126 SLEEP, 127 PARTIAL, 128 FULL 129 } 130 131 private static PhoneApp sMe; 132 133 // A few important fields we expose to the rest of the package 134 // directly (rather than thru set/get methods) for efficiency. 135 Phone phone; 136 CallNotifier notifier; 137 Ringer ringer; 138 BluetoothHandsfree mBtHandsfree; 139 PhoneInterfaceManager phoneMgr; 140 int mBluetoothHeadsetState = BluetoothHeadset.STATE_ERROR; 141 int mBluetoothHeadsetAudioState = BluetoothHeadset.STATE_ERROR; 142 boolean mShowBluetoothIndication = false; 143 144 // Internal PhoneApp Call state tracker 145 CdmaPhoneCallState cdmaPhoneCallState; 146 147 // The InCallScreen instance (or null if the InCallScreen hasn't been 148 // created yet.) 149 private InCallScreen mInCallScreen; 150 151 // The currently-active PUK entry activity and progress dialog. 152 // Normally, these are the Emergency Dialer and the subsequent 153 // progress dialog. null if there is are no such objects in 154 // the foreground. 155 private Activity mPUKEntryActivity; 156 private ProgressDialog mPUKEntryProgressDialog; 157 158 private boolean mIsSimPinEnabled; 159 private String mCachedSimPin; 160 161 // True if a wired headset is currently plugged in, based on the state 162 // from the latest Intent.ACTION_HEADSET_PLUG broadcast we received in 163 // mReceiver.onReceive(). 164 private boolean mIsHeadsetPlugged; 165 166 // True if the keyboard is currently *not* hidden 167 // Gets updated whenever there is a Configuration change 168 private boolean mIsHardKeyboardOpen; 169 170 // True if we are beginning a call, but the phone state has not changed yet 171 private boolean mBeginningCall; 172 173 // Last phone state seen by updatePhoneState() 174 Phone.State mLastPhoneState = Phone.State.IDLE; 175 176 private WakeState mWakeState = WakeState.SLEEP; 177 private ScreenTimeoutDuration mScreenTimeoutDuration = ScreenTimeoutDuration.DEFAULT; 178 private boolean mIgnoreTouchUserActivity = false; 179 private IBinder mPokeLockToken = new Binder(); 180 private IPowerManager mPowerManagerService; 181 private PowerManager.WakeLock mWakeLock; 182 private PowerManager.WakeLock mPartialWakeLock; 183 private PowerManager.WakeLock mProximityWakeLock; 184 private KeyguardManager mKeyguardManager; 185 private KeyguardManager.KeyguardLock mKeyguardLock; 186 private int mKeyguardDisableCount; 187 188 // Broadcast receiver for various intent broadcasts (see onCreate()) 189 private final BroadcastReceiver mReceiver = new PhoneAppBroadcastReceiver(); 190 191 // Broadcast receiver purely for ACTION_MEDIA_BUTTON broadcasts 192 private final BroadcastReceiver mMediaButtonReceiver = new MediaButtonBroadcastReceiver(); 193 194 /** boolean indicating restoring mute state on InCallScreen.onResume() */ 195 private boolean mShouldRestoreMuteOnInCallResume; 196 197 // Following are the CDMA OTA information Objects used during OTA Call. 198 // cdmaOtaProvisionData object store static OTA information that needs 199 // to be maintained even during Slider open/close scenarios. 200 // cdmaOtaConfigData object stores configuration info to control visiblity 201 // of each OTA Screens. 202 // cdmaOtaScreenState object store OTA Screen State information. 203 public OtaUtils.CdmaOtaProvisionData cdmaOtaProvisionData; 204 public OtaUtils.CdmaOtaConfigData cdmaOtaConfigData; 205 public OtaUtils.CdmaOtaScreenState cdmaOtaScreenState; 206 public OtaUtils.CdmaOtaInCallScreenUiState cdmaOtaInCallScreenUiState; 207 208 /** 209 * Set the restore mute state flag. Used when we are setting the mute state 210 * OUTSIDE of user interaction {@link PhoneUtils#startNewCall(Phone)} 211 */ 212 /*package*/void setRestoreMuteOnInCallResume (boolean mode) { 213 mShouldRestoreMuteOnInCallResume = mode; 214 } 215 216 /** 217 * Get the restore mute state flag. 218 * This is used by the InCallScreen {@link InCallScreen#onResume()} to figure 219 * out if we need to restore the mute state for the current active call. 220 */ 221 /*package*/boolean getRestoreMuteOnInCallResume () { 222 return mShouldRestoreMuteOnInCallResume; 223 } 224 225 Handler mHandler = new Handler() { 226 @Override 227 public void handleMessage(Message msg) { 228 switch (msg.what) { 229 case EVENT_SIM_LOCKED: 230// mIsSimPinEnabled = true; 231// 232// if (Config.LOGV) Log.v(LOG_TAG, "show sim unlock panel"); 233// SimPinUnlockPanel pinUnlockPanel = new SimPinUnlockPanel( 234// PhoneApp.getInstance()); 235// pinUnlockPanel.show(); 236 break; 237 238 case EVENT_SIM_ABSENT: 239// Don't need this now that the lock screen handles this case 240// if (Config.LOGV) Log.v(LOG_TAG, "show sim missing panel"); 241// SimMissingPanel missingPanel = new SimMissingPanel( 242// PhoneApp.getInstance()); 243// missingPanel.show(); 244 break; 245 246 case EVENT_SIM_NETWORK_LOCKED: 247 if (getResources().getBoolean(R.bool.ignore_sim_network_locked_events)) { 248 // Some products don't have the concept of a "SIM network lock" 249 Log.i(LOG_TAG, "Ignoring EVENT_SIM_NETWORK_LOCKED event; " 250 + "not showing 'SIM network unlock' PIN entry screen"); 251 } else { 252 // Normal case: show the "SIM network unlock" PIN entry screen. 253 // The user won't be able to do anything else until 254 // they enter a valid SIM network PIN. 255 Log.i(LOG_TAG, "show sim depersonal panel"); 256 IccNetworkDepersonalizationPanel ndpPanel = 257 new IccNetworkDepersonalizationPanel(PhoneApp.getInstance()); 258 ndpPanel.show(); 259 } 260 break; 261 262 case EVENT_UPDATE_INCALL_NOTIFICATION: 263 // Tell the NotificationMgr to update the "ongoing 264 // call" icon in the status bar, if necessary. 265 // Currently, this is triggered by a bluetooth headset 266 // state change (since the status bar icon needs to 267 // turn blue when bluetooth is active.) 268 NotificationMgr.getDefault().updateInCallNotification(); 269 break; 270 271 case EVENT_DATA_ROAMING_DISCONNECTED: 272 NotificationMgr.getDefault().showDataDisconnectedRoaming(); 273 break; 274 275 case EVENT_DATA_ROAMING_OK: 276 NotificationMgr.getDefault().hideDataDisconnectedRoaming(); 277 break; 278 279 case MMI_COMPLETE: 280 onMMIComplete((AsyncResult) msg.obj); 281 break; 282 283 case MMI_CANCEL: 284 PhoneUtils.cancelMmiCode(phone); 285 break; 286 287 case EVENT_WIRED_HEADSET_PLUG: 288 // Since the presence of a wired headset or bluetooth affects the 289 // speakerphone, update the "speaker" state. We ONLY want to do 290 // this on the wired headset connect / disconnect events for now 291 // though, so we're only triggering on EVENT_WIRED_HEADSET_PLUG. 292 // If in call screen is showing, let InCallScreen handle the speaker. 293 294 Phone.State phoneState = phone.getState(); 295 // Do not change speaker state if phone is not off hook 296 if (phoneState == Phone.State.OFFHOOK) { 297 if (!isShowingCallScreen() && 298 (mBtHandsfree == null || !mBtHandsfree.isAudioOn())) { 299 if (!isHeadsetPlugged()) { 300 // if the state is "not connected", restore the speaker state. 301 PhoneUtils.restoreSpeakerMode(getApplicationContext()); 302 } else { 303 // if the state is "connected", force the speaker off without 304 // storing the state. 305 PhoneUtils.turnOnSpeaker(getApplicationContext(), false, false); 306 } 307 } 308 } 309 // Update the Proximity sensor based on headset state 310 updateProximitySensorMode(phoneState); 311 break; 312 313 case EVENT_SIM_STATE_CHANGED: 314 // Marks the event where the SIM goes into ready state. 315 // Right now, this is only used for the PUK-unlocking 316 // process. 317 if (msg.obj.equals(IccCard.INTENT_VALUE_ICC_READY)) { 318 // when the right event is triggered and there 319 // are UI objects in the foreground, we close 320 // them to display the lock panel. 321 if (mPUKEntryActivity != null) { 322 mPUKEntryActivity.finish(); 323 mPUKEntryActivity = null; 324 } 325 if (mPUKEntryProgressDialog != null) { 326 mPUKEntryProgressDialog.dismiss(); 327 mPUKEntryProgressDialog = null; 328 } 329 } 330 break; 331 332 case EVENT_UNSOL_CDMA_INFO_RECORD: 333 //TODO: handle message here; 334 break; 335 } 336 } 337 }; 338 339 public PhoneApp() { 340 sMe = this; 341 } 342 343 @Override 344 public void onCreate() { 345 if (Config.LOGV) Log.v(LOG_TAG, "onCreate()..."); 346 347 ContentResolver resolver = getContentResolver(); 348 349 if (phone == null) { 350 // Initialize the telephony framework 351 PhoneFactory.makeDefaultPhones(this); 352 353 // Get the default phone 354 phone = PhoneFactory.getDefaultPhone(); 355 356 NotificationMgr.init(this); 357 358 phoneMgr = new PhoneInterfaceManager(this, phone); 359 360 int phoneType = phone.getPhoneType(); 361 362 if (phoneType == Phone.PHONE_TYPE_CDMA) { 363 // Create an instance of CdmaPhoneCallState and initialize it to IDLE 364 cdmaPhoneCallState = new CdmaPhoneCallState(); 365 cdmaPhoneCallState.CdmaPhoneCallStateInit(); 366 } 367 368 if (getSystemService(Context.BLUETOOTH_SERVICE) != null) { 369 mBtHandsfree = new BluetoothHandsfree(this, phone); 370 startService(new Intent(this, BluetoothHeadsetService.class)); 371 } else { 372 // Device is not bluetooth capable 373 mBtHandsfree = null; 374 } 375 376 ringer = new Ringer(phone); 377 378 // before registering for phone state changes 379 PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE); 380 mWakeLock = pm.newWakeLock(PowerManager.FULL_WAKE_LOCK 381 | PowerManager.ACQUIRE_CAUSES_WAKEUP 382 | PowerManager.ON_AFTER_RELEASE, LOG_TAG); 383 // lock used to keep the processor awake, when we don't care for the display. 384 mPartialWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK 385 | PowerManager.ON_AFTER_RELEASE, LOG_TAG); 386 // Wake lock used to control proximity sensor behavior. 387 if ((pm.getSupportedWakeLockFlags() 388 & PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK) != 0x0) { 389 mProximityWakeLock = 390 pm.newWakeLock(PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK, LOG_TAG); 391 } 392 if (DBG) Log.d(LOG_TAG, "mProximityWakeLock: " + mProximityWakeLock); 393 394 mKeyguardManager = (KeyguardManager) getSystemService(Context.KEYGUARD_SERVICE); 395 mKeyguardLock = mKeyguardManager.newKeyguardLock(LOG_TAG); 396 397 // get a handle to the service so that we can use it later when we 398 // want to set the poke lock. 399 mPowerManagerService = IPowerManager.Stub.asInterface( 400 ServiceManager.getService("power")); 401 402 notifier = new CallNotifier(this, phone, ringer, mBtHandsfree); 403 404 // register for ICC status 405 IccCard sim = phone.getIccCard(); 406 if (sim != null) { 407 if (Config.LOGV) Log.v(LOG_TAG, "register for ICC status"); 408 sim.registerForAbsent(mHandler, EVENT_SIM_ABSENT, null); 409 sim.registerForLocked(mHandler, EVENT_SIM_LOCKED, null); 410 sim.registerForNetworkLocked(mHandler, EVENT_SIM_NETWORK_LOCKED, null); 411 } 412 413 // register for MMI/USSD 414 if (phoneType == Phone.PHONE_TYPE_GSM) { 415 phone.registerForMmiComplete(mHandler, MMI_COMPLETE, null); 416 } 417 418 // register connection tracking to PhoneUtils 419 PhoneUtils.initializeConnectionHandler(phone); 420 421 // Register for misc other intent broadcasts. 422 IntentFilter intentFilter = 423 new IntentFilter(Intent.ACTION_AIRPLANE_MODE_CHANGED); 424 intentFilter.addAction(BluetoothHeadset.ACTION_STATE_CHANGED); 425 intentFilter.addAction(BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED); 426 intentFilter.addAction(TelephonyIntents.ACTION_ANY_DATA_CONNECTION_STATE_CHANGED); 427 intentFilter.addAction(Intent.ACTION_HEADSET_PLUG); 428 intentFilter.addAction(Intent.ACTION_BATTERY_LOW); 429 intentFilter.addAction(TelephonyIntents.ACTION_SIM_STATE_CHANGED); 430 intentFilter.addAction(TelephonyIntents.ACTION_RADIO_TECHNOLOGY_CHANGED); 431 intentFilter.addAction(TelephonyIntents.ACTION_SERVICE_STATE_CHANGED); 432 intentFilter.addAction(TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED); 433 registerReceiver(mReceiver, intentFilter); 434 435 // Use a separate receiver for ACTION_MEDIA_BUTTON broadcasts, 436 // since we need to manually adjust its priority (to make sure 437 // we get these intents *before* the media player.) 438 IntentFilter mediaButtonIntentFilter = 439 new IntentFilter(Intent.ACTION_MEDIA_BUTTON); 440 // 441 // Make sure we're higher priority than the media player's 442 // MediaButtonIntentReceiver (which currently has the default 443 // priority of zero; see apps/Music/AndroidManifest.xml.) 444 mediaButtonIntentFilter.setPriority(1); 445 // 446 registerReceiver(mMediaButtonReceiver, mediaButtonIntentFilter); 447 448 //set the default values for the preferences in the phone. 449 PreferenceManager.setDefaultValues(this, R.xml.network_setting, false); 450 451 PreferenceManager.setDefaultValues(this, R.xml.call_feature_setting, false); 452 453 // Make sure the audio mode (along with some 454 // audio-mode-related state of our own) is initialized 455 // correctly, given the current state of the phone. 456 switch (phone.getState()) { 457 case IDLE: 458 if (DBG) Log.d(LOG_TAG, "Resetting audio state/mode: IDLE"); 459 PhoneUtils.setAudioControlState(PhoneUtils.AUDIO_IDLE); 460 PhoneUtils.setAudioMode(this, AudioManager.MODE_NORMAL); 461 break; 462 case RINGING: 463 if (DBG) Log.d(LOG_TAG, "Resetting audio state/mode: RINGING"); 464 PhoneUtils.setAudioControlState(PhoneUtils.AUDIO_RINGING); 465 PhoneUtils.setAudioMode(this, AudioManager.MODE_RINGTONE); 466 break; 467 case OFFHOOK: 468 if (DBG) Log.d(LOG_TAG, "Resetting audio state/mode: OFFHOOK"); 469 PhoneUtils.setAudioControlState(PhoneUtils.AUDIO_OFFHOOK); 470 PhoneUtils.setAudioMode(this, AudioManager.MODE_IN_CALL); 471 break; 472 } 473 } 474 475 boolean phoneIsCdma = (phone.getPhoneType() == Phone.PHONE_TYPE_CDMA); 476 477 if (phoneIsCdma) { 478 cdmaOtaProvisionData = new OtaUtils.CdmaOtaProvisionData(); 479 cdmaOtaConfigData = new OtaUtils.CdmaOtaConfigData(); 480 cdmaOtaScreenState = new OtaUtils.CdmaOtaScreenState(); 481 cdmaOtaInCallScreenUiState = new OtaUtils.CdmaOtaInCallScreenUiState(); 482 } 483 484 // XXX pre-load the SimProvider so that it's ready 485 resolver.getType(Uri.parse("content://icc/adn")); 486 487 // start with the default value to set the mute state. 488 mShouldRestoreMuteOnInCallResume = false; 489 490 // Register for Cdma Information Records 491 // TODO(Moto): Merge 492 // phone.registerCdmaInformationRecord(mHandler, EVENT_UNSOL_CDMA_INFO_RECORD, null); 493 494 // Read TTY settings and store it into BP NV. 495 // AP owns (i.e. stores) the TTY setting in AP settings database and pushes the setting 496 // to BP at power up (BP does not need to make the TTY setting persistent storage). 497 // This way, there is a single owner (i.e AP) for the TTY setting in the phone. 498 if (phoneIsCdma) { 499 int settingsTtyMode = android.provider.Settings.Secure.getInt( 500 phone.getContext().getContentResolver(), 501 android.provider.Settings.Secure.PREFERRED_TTY_MODE, 502 Phone.TTY_MODE_OFF); 503 phone.setTTYMode(settingsTtyMode, null); 504 } 505 } 506 507 @Override 508 public void onConfigurationChanged(Configuration newConfig) { 509 if (newConfig.hardKeyboardHidden == Configuration.HARDKEYBOARDHIDDEN_NO) { 510 mIsHardKeyboardOpen = true; 511 } else { 512 mIsHardKeyboardOpen = false; 513 } 514 515 // Update the Proximity sensor based on keyboard state 516 updateProximitySensorMode(phone.getState()); 517 super.onConfigurationChanged(newConfig); 518 } 519 520 /** 521 * Returns the singleton instance of the PhoneApp. 522 */ 523 static PhoneApp getInstance() { 524 return sMe; 525 } 526 527 Ringer getRinger() { 528 return ringer; 529 } 530 531 BluetoothHandsfree getBluetoothHandsfree() { 532 return mBtHandsfree; 533 } 534 535 static Intent createCallLogIntent() { 536 Intent intent = new Intent(Intent.ACTION_VIEW, null); 537 intent.setType("vnd.android.cursor.dir/calls"); 538 return intent; 539 } 540 541 /** 542 * Return an Intent that can be used to bring up the in-call screen. 543 * 544 * This intent can only be used from within the Phone app, since the 545 * InCallScreen is not exported from our AndroidManifest. 546 */ 547 /* package */ static Intent createInCallIntent() { 548 Intent intent = new Intent(Intent.ACTION_MAIN, null); 549 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK 550 | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS 551 | Intent.FLAG_ACTIVITY_NO_USER_ACTION); 552 intent.setClassName("com.android.phone", getCallScreenClassName()); 553 return intent; 554 } 555 556 /** 557 * Variation of createInCallIntent() that also specifies whether the 558 * DTMF dialpad should be initially visible when the InCallScreen 559 * comes up. 560 */ 561 /* package */ static Intent createInCallIntent(boolean showDialpad) { 562 Intent intent = createInCallIntent(); 563 intent.putExtra(InCallScreen.SHOW_DIALPAD_EXTRA, showDialpad); 564 return intent; 565 } 566 567 static String getCallScreenClassName() { 568 return InCallScreen.class.getName(); 569 } 570 571 /** 572 * Starts the InCallScreen Activity. 573 */ 574 void displayCallScreen() { 575 if (VDBG) Log.d(LOG_TAG, "displayCallScreen()..."); 576 startActivity(createInCallIntent()); 577 Profiler.callScreenRequested(); 578 } 579 580 /** 581 * Helper function to check for one special feature of the CALL key: 582 * Normally, when the phone is idle, CALL takes you to the call log 583 * (see the handler for KEYCODE_CALL in PhoneWindow.onKeyUp().) 584 * But if the phone is in use (either off-hook or ringing) we instead 585 * handle the CALL button by taking you to the in-call UI. 586 * 587 * @return true if we intercepted the CALL keypress (i.e. the phone 588 * was in use) 589 * 590 * @see DialerActivity#onCreate 591 */ 592 boolean handleInCallOrRinging() { 593 if (phone.getState() != Phone.State.IDLE) { 594 // Phone is OFFHOOK or RINGING. 595 if (DBG) Log.v(LOG_TAG, 596 "handleInCallOrRinging: show call screen"); 597 displayCallScreen(); 598 return true; 599 } 600 return false; 601 } 602 603 boolean isSimPinEnabled() { 604 return mIsSimPinEnabled; 605 } 606 607 boolean authenticateAgainstCachedSimPin(String pin) { 608 return (mCachedSimPin != null && mCachedSimPin.equals(pin)); 609 } 610 611 void setCachedSimPin(String pin) { 612 mCachedSimPin = pin; 613 } 614 615 void setInCallScreenInstance(InCallScreen inCallScreen) { 616 mInCallScreen = inCallScreen; 617 } 618 619 /** 620 * @return true if the in-call UI is running as the foreground 621 * activity. (In other words, from the perspective of the 622 * InCallScreen activity, return true between onResume() and 623 * onPause().) 624 * 625 * Note this method will return false if the screen is currently off, 626 * even if the InCallScreen *was* in the foreground just before the 627 * screen turned off. (This is because the foreground activity is 628 * always "paused" while the screen is off.) 629 */ 630 boolean isShowingCallScreen() { 631 if (mInCallScreen == null) return false; 632 return mInCallScreen.isForegroundActivity(); 633 } 634 635 /** 636 * Dismisses the in-call UI. 637 * 638 * This also ensures that you won't be able to get back to the in-call 639 * UI via the BACK button (since this call removes the InCallScreen 640 * from the activity history.) 641 * For OTA Call, it call InCallScreen api to handle OTA Call End scenario 642 * to display OTA Call End screen. 643 */ 644 void dismissCallScreen() { 645 if (mInCallScreen != null) { 646 if (mInCallScreen.isOtaCallInActiveState() 647 || mInCallScreen.isOtaCallInEndState() 648 || ((cdmaOtaScreenState != null) 649 && (cdmaOtaScreenState.otaScreenState 650 != CdmaOtaScreenState.OtaScreenState.OTA_STATUS_UNDEFINED))) { 651 // TODO(Moto): During OTA Call, display should not become dark to 652 // allow user to see OTA UI update. Phone app needs to hold a SCREEN_DIM_WAKE_LOCK 653 // wake lock during the entire OTA call. 654 wakeUpScreen(); 655 // If InCallScreen is not in foreground we resume it to show the OTA call end screen 656 // Fire off the InCallScreen intent 657 displayCallScreen(); 658 659 mInCallScreen.handleOtaCallEnd(); 660 return; 661 } else { 662 mInCallScreen.finish(); 663 } 664 } 665 } 666 667 /** 668 * Handle OTA events 669 * 670 * When OTA call is active and display becomes dark, then CallNotifier will 671 * handle OTA Events by calling this api which then calls OtaUtil function. 672 */ 673 void handleOtaEvents(Message msg) { 674 675 if (DBG) Log.d(LOG_TAG, "Enter handleOtaEvents"); 676 if ((mInCallScreen != null) && (!isShowingCallScreen())) { 677 if (mInCallScreen.otaUtils != null) { 678 mInCallScreen.otaUtils.onOtaProvisionStatusChanged((AsyncResult) msg.obj); 679 } 680 } 681 } 682 683 684 /** 685 * Sets the activity responsible for un-PUK-blocking the device 686 * so that we may close it when we receive a positive result. 687 * mPUKEntryActivity is also used to indicate to the device that 688 * we are trying to un-PUK-lock the phone. In other words, iff 689 * it is NOT null, then we are trying to unlock and waiting for 690 * the SIM to move to READY state. 691 * 692 * @param activity is the activity to close when PUK has 693 * finished unlocking. Can be set to null to indicate the unlock 694 * or SIM READYing process is over. 695 */ 696 void setPukEntryActivity(Activity activity) { 697 mPUKEntryActivity = activity; 698 } 699 700 Activity getPUKEntryActivity() { 701 return mPUKEntryActivity; 702 } 703 704 /** 705 * Sets the dialog responsible for notifying the user of un-PUK- 706 * blocking - SIM READYing progress, so that we may dismiss it 707 * when we receive a positive result. 708 * 709 * @param dialog indicates the progress dialog informing the user 710 * of the state of the device. Dismissed upon completion of 711 * READYing process 712 */ 713 void setPukEntryProgressDialog(ProgressDialog dialog) { 714 mPUKEntryProgressDialog = dialog; 715 } 716 717 ProgressDialog getPUKEntryProgressDialog() { 718 return mPUKEntryProgressDialog; 719 } 720 721 /** 722 * Disables the keyguard. This is used by the phone app to allow 723 * interaction with the Phone UI when the keyguard would otherwise be 724 * active (like receiving an incoming call while the device is 725 * locked.) 726 * 727 * Any call to this method MUST be followed (eventually) 728 * by a corresponding reenableKeyguard() call. 729 */ 730 /* package */ void disableKeyguard() { 731 if (DBG) Log.d(LOG_TAG, "disable keyguard"); 732 // if (DBG) Log.d(LOG_TAG, "disableKeyguard()...", new Throwable("stack dump")); 733 synchronized (mKeyguardLock) { 734 if (mKeyguardDisableCount++ == 0) { 735 mKeyguardLock.disableKeyguard(); 736 } 737 } 738 } 739 740 /** 741 * Re-enables the keyguard after a previous disableKeyguard() call. 742 * 743 * Any call to this method MUST correspond to (i.e. be balanced with) 744 * a previous disableKeyguard() call. 745 */ 746 /* package */ void reenableKeyguard() { 747 if (DBG) Log.d(LOG_TAG, "re-enable keyguard"); 748 // if (DBG) Log.d(LOG_TAG, "reenableKeyguard()...", new Throwable("stack dump")); 749 synchronized (mKeyguardLock) { 750 if (mKeyguardDisableCount > 0) { 751 if (--mKeyguardDisableCount == 0) { 752 mKeyguardLock.reenableKeyguard(); 753 } 754 } else { 755 Log.e(LOG_TAG, "mKeyguardDisableCount is already zero"); 756 } 757 } 758 } 759 760 /** 761 * Controls how quickly the screen times out. 762 * 763 * The poke lock controls how long it takes before the screen powers 764 * down, and therefore has no immediate effect when the current 765 * WakeState (see {@link PhoneApp#requestWakeState}) is FULL. 766 * If we're in a state where the screen *is* allowed to turn off, 767 * though, the poke lock will determine the timeout interval (long or 768 * short). 769 * 770 * @param shortPokeLock tells the device the timeout duration to use 771 * before going to sleep 772 * {@link com.android.server.PowerManagerService#SHORT_KEYLIGHT_DELAY}. 773 */ 774 /* package */ void setScreenTimeout(ScreenTimeoutDuration duration) { 775 if (VDBG) Log.d(LOG_TAG, "setScreenTimeout(" + duration + ")..."); 776 777 // make sure we don't set the poke lock repeatedly so that we 778 // avoid triggering the userActivity calls in 779 // PowerManagerService.setPokeLock(). 780 if (duration == mScreenTimeoutDuration) { 781 return; 782 } 783 // stick with default timeout if we are using the proximity sensor 784 if (proximitySensorModeEnabled()) { 785 return; 786 } 787 mScreenTimeoutDuration = duration; 788 updatePokeLock(); 789 } 790 791 /** 792 * Update the state of the poke lock held by the phone app, 793 * based on the current desired screen timeout and the 794 * current "ignore user activity on touch" flag. 795 */ 796 private void updatePokeLock() { 797 // This is kind of convoluted, but the basic thing to remember is 798 // that the poke lock just sends a message to the screen to tell 799 // it to stay on for a while. 800 // The default is 0, for a long timeout and should be set that way 801 // when we are heading back into a the keyguard / screen off 802 // state, and also when we're trying to keep the screen alive 803 // while ringing. We'll also want to ignore the cheek events 804 // regardless of the timeout duration. 805 // The short timeout is really used whenever we want to give up 806 // the screen lock, such as when we're in call. 807 int pokeLockSetting = LocalPowerManager.POKE_LOCK_IGNORE_CHEEK_EVENTS; 808 switch (mScreenTimeoutDuration) { 809 case SHORT: 810 // Set the poke lock to timeout the display after a short 811 // timeout (5s). This ensures that the screen goes to sleep 812 // as soon as acceptably possible after we the wake lock 813 // has been released. 814 pokeLockSetting |= LocalPowerManager.POKE_LOCK_SHORT_TIMEOUT; 815 break; 816 817 case MEDIUM: 818 // Set the poke lock to timeout the display after a medium 819 // timeout (15s). This ensures that the screen goes to sleep 820 // as soon as acceptably possible after we the wake lock 821 // has been released. 822 pokeLockSetting |= LocalPowerManager.POKE_LOCK_MEDIUM_TIMEOUT; 823 break; 824 825 case DEFAULT: 826 default: 827 // set the poke lock to timeout the display after a long 828 // delay by default. 829 // TODO: it may be nice to be able to disable cheek presses 830 // for long poke locks (emergency dialer, for instance). 831 break; 832 } 833 834 if (mIgnoreTouchUserActivity) { 835 pokeLockSetting |= LocalPowerManager.POKE_LOCK_IGNORE_TOUCH_AND_CHEEK_EVENTS; 836 } 837 838 // Send the request 839 try { 840 mPowerManagerService.setPokeLock(pokeLockSetting, mPokeLockToken, LOG_TAG); 841 } catch (RemoteException e) { 842 Log.w(LOG_TAG, "mPowerManagerService.setPokeLock() failed: " + e); 843 } 844 } 845 846 /** 847 * Controls whether or not the screen is allowed to sleep. 848 * 849 * Once sleep is allowed (WakeState is SLEEP), it will rely on the 850 * settings for the poke lock to determine when to timeout and let 851 * the device sleep {@link PhoneApp#setScreenTimeout}. 852 * 853 * @param ws tells the device to how to wake. 854 */ 855 /* package */ void requestWakeState(WakeState ws) { 856 if (VDBG) Log.d(LOG_TAG, "requestWakeState(" + ws + ")..."); 857 if (mWakeState != ws) { 858 switch (ws) { 859 case PARTIAL: 860 // acquire the processor wake lock, and release the FULL 861 // lock if it is being held. 862 mPartialWakeLock.acquire(); 863 if (mWakeLock.isHeld()) { 864 mWakeLock.release(); 865 } 866 break; 867 case FULL: 868 // acquire the full wake lock, and release the PARTIAL 869 // lock if it is being held. 870 mWakeLock.acquire(); 871 if (mPartialWakeLock.isHeld()) { 872 mPartialWakeLock.release(); 873 } 874 break; 875 case SLEEP: 876 default: 877 // release both the PARTIAL and FULL locks. 878 if (mWakeLock.isHeld()) { 879 mWakeLock.release(); 880 } 881 if (mPartialWakeLock.isHeld()) { 882 mPartialWakeLock.release(); 883 } 884 break; 885 } 886 mWakeState = ws; 887 } 888 } 889 890 /** 891 * If we are not currently keeping the screen on, then poke the power 892 * manager to wake up the screen for the user activity timeout duration. 893 */ 894 /* package */ void wakeUpScreen() { 895 if (mWakeState == WakeState.SLEEP) { 896 if (DBG) Log.d(LOG_TAG, "pulse screen lock"); 897 try { 898 mPowerManagerService.userActivityWithForce(SystemClock.uptimeMillis(), false, true); 899 } catch (RemoteException ex) { 900 // Ignore -- the system process is dead. 901 } 902 } 903 } 904 905 /** 906 * Sets the wake state and screen timeout based on the current state 907 * of the phone, and the current state of the in-call UI. 908 * 909 * This method is a "UI Policy" wrapper around 910 * {@link PhoneApp#requestWakeState} and {@link PhoneApp#setScreenTimeout}. 911 * 912 * It's safe to call this method regardless of the state of the Phone 913 * (e.g. whether or not it's idle), and regardless of the state of the 914 * Phone UI (e.g. whether or not the InCallScreen is active.) 915 */ 916 /* package */ void updateWakeState() { 917 Phone.State state = phone.getState(); 918 919 // True if the in-call UI is the foreground activity. 920 // (Note this will be false if the screen is currently off, 921 // since in that case *no* activity is in the foreground.) 922 boolean isShowingCallScreen = isShowingCallScreen(); 923 924 // True if the InCallScreen's DTMF dialer is currently opened. 925 // (Note this does NOT imply whether or not the InCallScreen 926 // itself is visible.) 927 boolean isDialerOpened = (mInCallScreen != null) && mInCallScreen.isDialerOpened(); 928 929 // True if the speakerphone is in use. (If so, we *always* use 930 // the default timeout. Since the user is obviously not holding 931 // the phone up to his/her face, we don't need to worry about 932 // false touches, and thus don't need to turn the screen off so 933 // aggressively.) 934 // Note that we need to make a fresh call to this method any 935 // time the speaker state changes. (That happens in 936 // PhoneUtils.turnOnSpeaker().) 937 boolean isSpeakerInUse = (state == Phone.State.OFFHOOK) && PhoneUtils.isSpeakerOn(this); 938 939 // TODO (bug 1440854): The screen timeout *might* also need to 940 // depend on the bluetooth state, but this isn't as clear-cut as 941 // the speaker state (since while using BT it's common for the 942 // user to put the phone straight into a pocket, in which case the 943 // timeout should probably still be short.) 944 945 if (DBG) Log.d(LOG_TAG, "updateWakeState: callscreen " + isShowingCallScreen 946 + ", dialer " + isDialerOpened 947 + ", speaker " + isSpeakerInUse + "..."); 948 949 // 950 // (1) Set the screen timeout. 951 // 952 // Note that the "screen timeout" value we determine here is 953 // meaningless if the screen is forced on (see (2) below.) 954 // 955 if (!isShowingCallScreen || isSpeakerInUse) { 956 // Use the system-wide default timeout. 957 setScreenTimeout(ScreenTimeoutDuration.DEFAULT); 958 } else { 959 // We're on the in-call screen, and *not* using the speakerphone. 960 if (isDialerOpened) { 961 // The DTMF dialpad is up. This case is special because 962 // the in-call UI has its own "touch lock" mechanism to 963 // disable the dialpad after a very short amount of idle 964 // time (to avoid false touches from the user's face while 965 // in-call.) 966 // 967 // In this case the *physical* screen just uses the 968 // system-wide default timeout. 969 setScreenTimeout(ScreenTimeoutDuration.DEFAULT); 970 } else { 971 // We're on the in-call screen, and not using the DTMF dialpad. 972 // There's actually no touchable UI onscreen at all in 973 // this state. Also, the user is (most likely) not 974 // looking at the screen at all, since they're probably 975 // holding the phone up to their face. Here we use a 976 // special screen timeout value specific to the in-call 977 // screen, purely to save battery life. 978 setScreenTimeout(ScreenTimeoutDuration.MEDIUM); 979 } 980 } 981 982 // 983 // (2) Decide whether to force the screen on or not. 984 // 985 // Force the screen to be on if the phone is ringing or dialing, 986 // or if we're displaying the "Call ended" UI for a connection in 987 // the "disconnected" state. 988 // 989 boolean isRinging = (state == Phone.State.RINGING); 990 boolean isDialing = (phone.getForegroundCall().getState() == Call.State.DIALING); 991 boolean showingDisconnectedConnection = 992 PhoneUtils.hasDisconnectedConnections(phone) && isShowingCallScreen; 993 boolean keepScreenOn = isRinging || isDialing || showingDisconnectedConnection; 994 if (DBG) Log.d(LOG_TAG, "updateWakeState: keepScreenOn = " + keepScreenOn 995 + " (isRinging " + isRinging 996 + ", isDialing " + isDialing 997 + ", showingDisc " + showingDisconnectedConnection + ")"); 998 // keepScreenOn == true means we'll hold a full wake lock: 999 requestWakeState(keepScreenOn ? WakeState.FULL : WakeState.SLEEP); 1000 } 1001 1002 /** 1003 * Wrapper around the PowerManagerService.preventScreenOn() API. 1004 * This allows the in-call UI to prevent the screen from turning on 1005 * even if a subsequent call to updateWakeState() causes us to acquire 1006 * a full wake lock. 1007 */ 1008 /* package */ void preventScreenOn(boolean prevent) { 1009 if (VDBG) Log.d(LOG_TAG, "- preventScreenOn(" + prevent + ")..."); 1010 try { 1011 mPowerManagerService.preventScreenOn(prevent); 1012 } catch (RemoteException e) { 1013 Log.w(LOG_TAG, "mPowerManagerService.preventScreenOn() failed: " + e); 1014 } 1015 } 1016 1017 /** 1018 * Sets or clears the flag that tells the PowerManager that touch 1019 * (and cheek) events should NOT be considered "user activity". 1020 * 1021 * Since the in-call UI is totally insensitive to touch in most 1022 * states, we set this flag whenever the InCallScreen is in the 1023 * foreground. (Otherwise, repeated unintentional touches could 1024 * prevent the device from going to sleep.) 1025 * 1026 * There *are* some some touch events that really do count as user 1027 * activity, though. For those, we need to manually poke the 1028 * PowerManager's userActivity method; see pokeUserActivity(). 1029 */ 1030 /* package */ void setIgnoreTouchUserActivity(boolean ignore) { 1031 if (VDBG) Log.d(LOG_TAG, "setIgnoreTouchUserActivity(" + ignore + ")..."); 1032 mIgnoreTouchUserActivity = ignore; 1033 updatePokeLock(); 1034 } 1035 1036 /** 1037 * Manually pokes the PowerManager's userActivity method. Since we 1038 * hold the POKE_LOCK_IGNORE_TOUCH_AND_CHEEK_EVENTS poke lock while 1039 * the InCallScreen is active, we need to do this for touch events 1040 * that really do count as user activity (like DTMF key presses, or 1041 * unlocking the "touch lock" overlay.) 1042 */ 1043 /* package */ void pokeUserActivity() { 1044 if (VDBG) Log.d(LOG_TAG, "pokeUserActivity()..."); 1045 try { 1046 mPowerManagerService.userActivity(SystemClock.uptimeMillis(), false); 1047 } catch (RemoteException e) { 1048 Log.w(LOG_TAG, "mPowerManagerService.userActivity() failed: " + e); 1049 } 1050 } 1051 1052 /** 1053 * Set when a new outgoing call is beginning, so we can update 1054 * the proximity sensor state. 1055 * Cleared when the InCallScreen is no longer in the foreground, 1056 * in case the call fails without changing the telephony state. 1057 */ 1058 /* package */ void setBeginningCall(boolean beginning) { 1059 // Note that we are beginning a new call, for proximity sensor support 1060 mBeginningCall = beginning; 1061 // Update the Proximity sensor based on mBeginningCall state 1062 updateProximitySensorMode(phone.getState()); 1063 } 1064 1065 /** 1066 * Updates the wake lock used to control proximity sensor behavior, 1067 * based on the current state of the phone. This method is called 1068 * from the CallNotifier on any phone state change. 1069 * 1070 * On devices that have a proximity sensor, to avoid false touches 1071 * during a call, we hold a PROXIMITY_SCREEN_OFF_WAKE_LOCK wake lock 1072 * whenever the phone is off hook. (When held, that wake lock causes 1073 * the screen to turn off automatically when the sensor detects an 1074 * object close to the screen.) 1075 * 1076 * This method is a no-op for devices that don't have a proximity 1077 * sensor. 1078 * 1079 * Note this method doesn't care if the InCallScreen is the foreground 1080 * activity or not. That's because we want the proximity sensor to be 1081 * enabled any time the phone is in use, to avoid false cheek events 1082 * for whatever app you happen to be running. 1083 * 1084 * Proximity wake lock will *not* be held if any one of the 1085 * conditions is true while on a call: 1086 * 1) If the audio is routed via Bluetooth 1087 * 2) If a wired headset is connected 1088 * 3) if the speaker is ON 1089 * 4) If the slider is open(i.e. the hardkeyboard is *not* hidden) 1090 * 1091 * @param state current state of the phone (see {@link Phone#State}) 1092 */ 1093 /* package */ void updateProximitySensorMode(Phone.State state) { 1094 if (VDBG) Log.d(LOG_TAG, "updateProximitySensorMode: state = " + state); 1095 1096 if (proximitySensorModeEnabled()) { 1097 if (((state == Phone.State.OFFHOOK) || mBeginningCall) 1098 && !(isHeadsetPlugged() 1099 || PhoneUtils.isSpeakerOn(this) 1100 || ((mBtHandsfree != null) && mBtHandsfree.isAudioOn()) 1101 || mIsHardKeyboardOpen)) { 1102 // Phone is in use! Arrange for the screen to turn off 1103 // automatically when the sensor detects a close object. 1104 if (!mProximityWakeLock.isHeld()) { 1105 if (DBG) Log.d(LOG_TAG, "updateProximitySensorMode: acquiring..."); 1106 mProximityWakeLock.acquire(); 1107 // disable keyguard while we are using the proximity sensor 1108 disableKeyguard(); 1109 } else { 1110 if (VDBG) Log.d(LOG_TAG, "updateProximitySensorMode: lock already held."); 1111 } 1112 } else { 1113 // Phone is either idle, or ringing. We don't want any 1114 // special proximity sensor behavior in either case. 1115 if (mProximityWakeLock.isHeld()) { 1116 if (DBG) Log.d(LOG_TAG, "updateProximitySensorMode: releasing..."); 1117 mProximityWakeLock.release(); 1118 reenableKeyguard(); 1119 } else { 1120 if (VDBG) Log.d(LOG_TAG, "updateProximitySensorMode: lock already released."); 1121 } 1122 } 1123 } 1124 } 1125 1126 /** 1127 * Notifies the phone app when the phone state changes. 1128 * Currently used only for proximity sensor support. 1129 */ 1130 /* package */ void updatePhoneState(Phone.State state) { 1131 if (state != mLastPhoneState) { 1132 mLastPhoneState = state; 1133 updateProximitySensorMode(state); 1134 // clear our beginning call flag 1135 mBeginningCall = false; 1136 } 1137 } 1138 1139 /** 1140 * @return true if this device supports the "proximity sensor 1141 * auto-lock" feature while in-call (see updateProximitySensorMode()). 1142 */ 1143 /* package */ boolean proximitySensorModeEnabled() { 1144 return (mProximityWakeLock != null); 1145 } 1146 1147 KeyguardManager getKeyguardManager() { 1148 return mKeyguardManager; 1149 } 1150 1151 private void onMMIComplete(AsyncResult r) { 1152 if (VDBG) Log.d(LOG_TAG, "onMMIComplete()..."); 1153 MmiCode mmiCode = (MmiCode) r.result; 1154 PhoneUtils.displayMMIComplete(phone, getInstance(), mmiCode, null, null); 1155 } 1156 1157 private void initForNewRadioTechnology() { 1158 if (DBG) Log.d(LOG_TAG, "initForNewRadioTechnology..."); 1159 1160 if (phone.getPhoneType() == Phone.PHONE_TYPE_CDMA) { 1161 // Create an instance of CdmaPhoneCallState and initialize it to IDLE 1162 cdmaPhoneCallState = new CdmaPhoneCallState(); 1163 cdmaPhoneCallState.CdmaPhoneCallStateInit(); 1164 1165 //create instances of CDMA OTA data classes 1166 if (cdmaOtaProvisionData == null) { 1167 cdmaOtaProvisionData = new OtaUtils.CdmaOtaProvisionData(); 1168 } 1169 if (cdmaOtaConfigData == null) { 1170 cdmaOtaConfigData = new OtaUtils.CdmaOtaConfigData(); 1171 } 1172 if (cdmaOtaScreenState == null) { 1173 cdmaOtaScreenState = new OtaUtils.CdmaOtaScreenState(); 1174 } 1175 } 1176 1177 ringer.updateRingerContextAfterRadioTechnologyChange(this.phone); 1178 notifier.updateCallNotifierRegistrationsAfterRadioTechnologyChange(); 1179 if (mBtHandsfree != null) { 1180 mBtHandsfree.updateBtHandsfreeAfterRadioTechnologyChange(); 1181 } 1182 if (mInCallScreen != null) { 1183 mInCallScreen.updateAfterRadioTechnologyChange(); 1184 } 1185 1186 // Update registration for ICC status after radio technology change 1187 IccCard sim = phone.getIccCard(); 1188 if (sim != null) { 1189 if (DBG) Log.d(LOG_TAG, "Update registration for ICC status..."); 1190 1191 //Register all events new to the new active phone 1192 sim.registerForAbsent(mHandler, EVENT_SIM_ABSENT, null); 1193 sim.registerForLocked(mHandler, EVENT_SIM_LOCKED, null); 1194 sim.registerForNetworkLocked(mHandler, EVENT_SIM_NETWORK_LOCKED, null); 1195 } 1196 } 1197 1198 1199 /** 1200 * @return true if a wired headset is currently plugged in. 1201 * 1202 * @see Intent.ACTION_HEADSET_PLUG (which we listen for in mReceiver.onReceive()) 1203 */ 1204 boolean isHeadsetPlugged() { 1205 return mIsHeadsetPlugged; 1206 } 1207 1208 /** 1209 * @return true if the onscreen UI should currently be showing the 1210 * special "bluetooth is active" indication in a couple of places (in 1211 * which UI elements turn blue and/or show the bluetooth logo.) 1212 * 1213 * This depends on the BluetoothHeadset state *and* the current 1214 * telephony state; see shouldShowBluetoothIndication(). 1215 * 1216 * @see CallCard 1217 * @see NotificationMgr.updateInCallNotification 1218 */ 1219 /* package */ boolean showBluetoothIndication() { 1220 return mShowBluetoothIndication; 1221 } 1222 1223 /** 1224 * Recomputes the mShowBluetoothIndication flag based on the current 1225 * bluetooth state and current telephony state. 1226 * 1227 * This needs to be called any time the bluetooth headset state or the 1228 * telephony state changes. 1229 * 1230 * @param forceUiUpdate if true, force the UI elements that care 1231 * about this flag to update themselves. 1232 */ 1233 /* package */ void updateBluetoothIndication(boolean forceUiUpdate) { 1234 mShowBluetoothIndication = shouldShowBluetoothIndication(mBluetoothHeadsetState, 1235 mBluetoothHeadsetAudioState, 1236 phone); 1237 if (forceUiUpdate) { 1238 // Post Handler messages to the various components that might 1239 // need to be refreshed based on the new state. 1240 if (isShowingCallScreen()) mInCallScreen.requestUpdateBluetoothIndication(); 1241 mHandler.sendEmptyMessage(EVENT_UPDATE_INCALL_NOTIFICATION); 1242 } 1243 1244 // Update the Proximity sensor based on Bluetooth audio state 1245 updateProximitySensorMode(phone.getState()); 1246 } 1247 1248 /** 1249 * UI policy helper function for the couple of places in the UI that 1250 * have some way of indicating that "bluetooth is in use." 1251 * 1252 * @return true if the onscreen UI should indicate that "bluetooth is in use", 1253 * based on the specified bluetooth headset state, and the 1254 * current state of the phone. 1255 * @see showBluetoothIndication() 1256 */ 1257 private static boolean shouldShowBluetoothIndication(int bluetoothState, 1258 int bluetoothAudioState, 1259 Phone phone) { 1260 // We want the UI to indicate that "bluetooth is in use" in two 1261 // slightly different cases: 1262 // 1263 // (a) The obvious case: if a bluetooth headset is currently in 1264 // use for an ongoing call. 1265 // 1266 // (b) The not-so-obvious case: if an incoming call is ringing, 1267 // and we expect that audio *will* be routed to a bluetooth 1268 // headset once the call is answered. 1269 1270 switch (phone.getState()) { 1271 case OFFHOOK: 1272 // This covers normal active calls, and also the case if 1273 // the foreground call is DIALING or ALERTING. In this 1274 // case, bluetooth is considered "active" if a headset 1275 // is connected *and* audio is being routed to it. 1276 return ((bluetoothState == BluetoothHeadset.STATE_CONNECTED) 1277 && (bluetoothAudioState == BluetoothHeadset.AUDIO_STATE_CONNECTED)); 1278 1279 case RINGING: 1280 // If an incoming call is ringing, we're *not* yet routing 1281 // audio to the headset (since there's no in-call audio 1282 // yet!) In this case, if a bluetooth headset is 1283 // connected at all, we assume that it'll become active 1284 // once the user answers the phone. 1285 return (bluetoothState == BluetoothHeadset.STATE_CONNECTED); 1286 1287 default: // Presumably IDLE 1288 return false; 1289 } 1290 } 1291 1292 1293 /** 1294 * Receiver for misc intent broadcasts the Phone app cares about. 1295 */ 1296 private class PhoneAppBroadcastReceiver extends BroadcastReceiver { 1297 @Override 1298 public void onReceive(Context context, Intent intent) { 1299 String action = intent.getAction(); 1300 if (action.equals(Intent.ACTION_AIRPLANE_MODE_CHANGED)) { 1301 boolean enabled = System.getInt(getContentResolver(), 1302 System.AIRPLANE_MODE_ON, 0) == 0; 1303 phone.setRadioPower(enabled); 1304 } else if (action.equals(BluetoothHeadset.ACTION_STATE_CHANGED)) { 1305 mBluetoothHeadsetState = intent.getIntExtra(BluetoothHeadset.EXTRA_STATE, 1306 BluetoothHeadset.STATE_ERROR); 1307 if (VDBG) Log.d(LOG_TAG, "mReceiver: HEADSET_STATE_CHANGED_ACTION"); 1308 if (VDBG) Log.d(LOG_TAG, "==> new state: " + mBluetoothHeadsetState); 1309 updateBluetoothIndication(true); // Also update any visible UI if necessary 1310 } else if (action.equals(BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED)) { 1311 mBluetoothHeadsetAudioState = 1312 intent.getIntExtra(BluetoothHeadset.EXTRA_AUDIO_STATE, 1313 BluetoothHeadset.STATE_ERROR); 1314 if (VDBG) Log.d(LOG_TAG, "mReceiver: HEADSET_AUDIO_STATE_CHANGED_ACTION"); 1315 if (VDBG) Log.d(LOG_TAG, "==> new state: " + mBluetoothHeadsetAudioState); 1316 updateBluetoothIndication(true); // Also update any visible UI if necessary 1317 } else if (action.equals(TelephonyIntents.ACTION_ANY_DATA_CONNECTION_STATE_CHANGED)) { 1318 if (VDBG) Log.d(LOG_TAG, "mReceiver: ACTION_ANY_DATA_CONNECTION_STATE_CHANGED"); 1319 if (VDBG) Log.d(LOG_TAG, "- state: " + intent.getStringExtra(Phone.STATE_KEY)); 1320 if (VDBG) Log.d(LOG_TAG, "- reason: " 1321 + intent.getStringExtra(Phone.STATE_CHANGE_REASON_KEY)); 1322 1323 // The "data disconnected due to roaming" notification is 1324 // visible if you've lost data connectivity because you're 1325 // roaming and you have the "data roaming" feature turned off. 1326 boolean disconnectedDueToRoaming = false; 1327 if ("DISCONNECTED".equals(intent.getStringExtra(Phone.STATE_KEY))) { 1328 String reason = intent.getStringExtra(Phone.STATE_CHANGE_REASON_KEY); 1329 if (Phone.REASON_ROAMING_ON.equals(reason)) { 1330 // We just lost our data connection, and the reason 1331 // is that we started roaming. This implies that 1332 // the user has data roaming turned off. 1333 disconnectedDueToRoaming = true; 1334 } 1335 } 1336 mHandler.sendEmptyMessage(disconnectedDueToRoaming 1337 ? EVENT_DATA_ROAMING_DISCONNECTED 1338 : EVENT_DATA_ROAMING_OK); 1339 } else if (action.equals(Intent.ACTION_HEADSET_PLUG)) { 1340 if (VDBG) Log.d(LOG_TAG, "mReceiver: ACTION_HEADSET_PLUG"); 1341 if (VDBG) Log.d(LOG_TAG, " state: " + intent.getIntExtra("state", 0)); 1342 if (VDBG) Log.d(LOG_TAG, " name: " + intent.getStringExtra("name")); 1343 mIsHeadsetPlugged = (intent.getIntExtra("state", 0) == 1); 1344 mHandler.sendMessage(mHandler.obtainMessage(EVENT_WIRED_HEADSET_PLUG, 0)); 1345 } else if (action.equals(Intent.ACTION_BATTERY_LOW)) { 1346 if (VDBG) Log.d(LOG_TAG, "mReceiver: ACTION_BATTERY_LOW"); 1347 notifier.sendBatteryLow(); // Play a warning tone if in-call 1348 } else if ((action.equals(TelephonyIntents.ACTION_SIM_STATE_CHANGED)) && 1349 (mPUKEntryActivity != null)) { 1350 // if an attempt to un-PUK-lock the device was made, while we're 1351 // receiving this state change notification, notify the handler. 1352 // NOTE: This is ONLY triggered if an attempt to un-PUK-lock has 1353 // been attempted. 1354 mHandler.sendMessage(mHandler.obtainMessage(EVENT_SIM_STATE_CHANGED, 1355 intent.getStringExtra(IccCard.INTENT_KEY_ICC_STATE))); 1356 } else if (action.equals(TelephonyIntents.ACTION_RADIO_TECHNOLOGY_CHANGED)) { 1357 String newPhone = intent.getStringExtra(Phone.PHONE_NAME_KEY); 1358 Log.d(LOG_TAG, "Radio technology switched. Now " + newPhone + " is active."); 1359 initForNewRadioTechnology(); 1360 } else if (action.equals(TelephonyIntents.ACTION_SERVICE_STATE_CHANGED)) { 1361 handleServiceStateChanged(intent); 1362 } else if (action.equals(TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED)) { 1363 if (phone.getPhoneType() == Phone.PHONE_TYPE_CDMA) { 1364 Log.d(LOG_TAG, "Emergency Callback Mode arrived in PhoneApp."); 1365 // Start Emergency Callback Mode service 1366 if (intent.getBooleanExtra("phoneinECMState", false)) { 1367 context.startService(new Intent(context, 1368 EmergencyCallbackModeService.class)); 1369 } 1370 } else { 1371 Log.e(LOG_TAG, "Error! Emergency Callback Mode not supported for " + 1372 phone.getPhoneName() + " phones"); 1373 } 1374 } 1375 } 1376 } 1377 1378 /** 1379 * Broadcast receiver for the ACTION_MEDIA_BUTTON broadcast intent. 1380 * 1381 * This functionality isn't lumped in with the other intents in 1382 * PhoneAppBroadcastReceiver because we instantiate this as a totally 1383 * separate BroadcastReceiver instance, since we need to manually 1384 * adjust its IntentFilter's priority (to make sure we get these 1385 * intents *before* the media player.) 1386 */ 1387 private class MediaButtonBroadcastReceiver extends BroadcastReceiver { 1388 @Override 1389 public void onReceive(Context context, Intent intent) { 1390 KeyEvent event = (KeyEvent) intent.getParcelableExtra(Intent.EXTRA_KEY_EVENT); 1391 if (VDBG) Log.d(LOG_TAG, 1392 "MediaButtonBroadcastReceiver.onReceive()... event = " + event); 1393 if ((event != null) 1394 && (event.getKeyCode() == KeyEvent.KEYCODE_HEADSETHOOK) 1395 && (event.getAction() == KeyEvent.ACTION_DOWN)) { 1396 1397 if (event.getRepeatCount() == 0) { 1398 // Mute ONLY on the initial keypress. 1399 if (VDBG) Log.d(LOG_TAG, "MediaButtonBroadcastReceiver: HEADSETHOOK down!"); 1400 boolean consumed = PhoneUtils.handleHeadsetHook(phone); 1401 if (VDBG) Log.d(LOG_TAG, "==> handleHeadsetHook(): consumed = " + consumed); 1402 if (consumed) { 1403 // If a headset is attached and the press is consumed, also update 1404 // any UI items (such as an InCallScreen mute button) that may need to 1405 // be updated if their state changed. 1406 if (isShowingCallScreen()) { 1407 mInCallScreen.requestUpdateTouchUi(); 1408 } 1409 abortBroadcast(); 1410 } 1411 } else if (phone.getState() != Phone.State.IDLE) { 1412 // As for any DOWN events other than the initial press, we consume 1413 // (and ignore) those too if the phone is in use. (Otherwise the 1414 // music player will handle them, which would be confusing.) 1415 abortBroadcast(); 1416 } 1417 } 1418 } 1419 } 1420 1421 private void handleServiceStateChanged(Intent intent) { 1422 /** 1423 * This used to handle updating EriTextWidgetProvider this routine 1424 * and and listening for ACTION_SERVICE_STATE_CHANGED intents could 1425 * be removed. But leaving just in case it might be needed in the near 1426 * future. 1427 */ 1428 1429 // If service just returned, start sending out the queued messages 1430 ServiceState ss = ServiceState.newFromBundle(intent.getExtras()); 1431 1432 boolean hasService = true; 1433 boolean isCdma = false; 1434 String eriText = ""; 1435 1436 if (ss != null) { 1437 int state = ss.getState(); 1438 NotificationMgr.getDefault().updateNetworkSelection(state); 1439 switch (state) { 1440 case ServiceState.STATE_OUT_OF_SERVICE: 1441 case ServiceState.STATE_POWER_OFF: 1442 hasService = false; 1443 break; 1444 } 1445 } else { 1446 hasService = false; 1447 } 1448 } 1449 1450 public boolean isOtaCallInActiveState() { 1451 boolean otaCallActive = false; 1452 if (mInCallScreen != null) { 1453 otaCallActive = mInCallScreen.isOtaCallInActiveState(); 1454 } 1455 if (DBG) Log.d(LOG_TAG, "PhoneApp - isOtaCallInActiveState " + otaCallActive); 1456 return otaCallActive; 1457 } 1458 1459 public boolean isOtaCallInEndState() { 1460 boolean otaCallEnded = false; 1461 if (mInCallScreen != null) { 1462 otaCallEnded = mInCallScreen.isOtaCallInEndState(); 1463 } 1464 if (DBG) Log.d(LOG_TAG, "PhoneApp - isOtaCallInEndState " + otaCallEnded); 1465 return otaCallEnded; 1466 } 1467 1468 // it is safe to call clearOtaState() even if the InCallScreen isn't active 1469 public void clearOtaState() { 1470 if (DBG) Log.d(LOG_TAG, "PhoneApp - clearOtaState ..."); 1471 if ((mInCallScreen != null) 1472 && (mInCallScreen.otaUtils != null)) { 1473 mInCallScreen.otaUtils.cleanOtaScreen(); 1474 if (DBG) Log.d(LOG_TAG, "PhoneApp - clearOtaState clears OTA screen"); 1475 } 1476 } 1477 1478 // it is safe to call dismissOtaDialogs() even if the InCallScreen isn't active 1479 public void dismissOtaDialogs() { 1480 if (DBG) Log.d(LOG_TAG, "PhoneApp - dismissOtaDialogs ..."); 1481 if ((mInCallScreen != null) 1482 && (mInCallScreen.otaUtils != null)) { 1483 mInCallScreen.otaUtils.dismissAllOtaDialogs(); 1484 if (DBG) Log.d(LOG_TAG, "PhoneApp - dismissOtaDialogs clears OTA dialogs"); 1485 } 1486 } 1487 1488 // it is safe to call clearInCallScreenMode() even if the InCallScreen isn't active 1489 public void clearInCallScreenMode() { 1490 if (DBG) Log.d(LOG_TAG, "PhoneApp - clearInCallScreenMode ..."); 1491 if (mInCallScreen != null) { 1492 mInCallScreen.resetInCallScreenMode(); 1493 } 1494 } 1495} 1496