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