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