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