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