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