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 20 21 import android.app.Activity; 22 import android.app.Application; 23 import android.app.KeyguardManager; 24 import android.app.ProgressDialog; 25 import android.bluetooth.BluetoothHeadset; 26 import android.bluetooth.BluetoothIntent; 27 import android.content.BroadcastReceiver; 28 import android.content.ContentResolver; 29 import android.content.Context; 30 import android.content.Intent; 31 import android.content.IntentFilter; 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.cdma.EriInfo; 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 61 /** 62 * Top-level Application class for the Phone app. 63 */ 64 public class PhoneApp extends Application { 65 /* package */ static final String LOG_TAG = "PhoneApp"; 66 67 /** 68 * Phone app-wide debug level: 69 * 0 - no debug logging 70 * 1 - normal debug logging if ro.debuggable is set (which is true in 71 * "eng" and "userdebug" builds but not "user" builds) 72 * 2 - ultra-verbose debug logging 73 * 74 * Most individual classes in the phone app have a local DBG constant, 75 * typically set to 76 * (PhoneApp.DBG_LEVEL >= 1) && (SystemProperties.getInt("ro.debuggable", 0) == 1) 77 * or else 78 * (PhoneApp.DBG_LEVEL >= 2) 79 * depending on the desired verbosity. 80 */ 81 /* package */ static final int DBG_LEVEL = 1; 82 83 private static final boolean DBG = 84 (PhoneApp.DBG_LEVEL >= 1) && (SystemProperties.getInt("ro.debuggable", 0) == 1); 85 private static final boolean VDBG = (PhoneApp.DBG_LEVEL >= 2); 86 87 // Message codes; see mHandler below. 88 private static final int EVENT_SIM_ABSENT = 1; 89 private static final int EVENT_SIM_LOCKED = 2; 90 private static final int EVENT_SIM_NETWORK_LOCKED = 3; 91 private static final int EVENT_WIRED_HEADSET_PLUG = 7; 92 private static final int EVENT_SIM_STATE_CHANGED = 8; 93 private static final int EVENT_UPDATE_INCALL_NOTIFICATION = 9; 94 private static final int EVENT_DATA_ROAMING_DISCONNECTED = 10; 95 private static final int EVENT_DATA_ROAMING_OK = 11; 96 private static final int EVENT_UNSOL_CDMA_INFO_RECORD = 12; 97 98 // The MMI codes are also used by the InCallScreen. 99 public static final int MMI_INITIATE = 51; 100 public static final int MMI_COMPLETE = 52; 101 public static final int MMI_CANCEL = 53; 102 // Don't use message codes larger than 99 here; those are reserved for 103 // the individual Activities of the Phone UI. 104 105 /** 106 * Allowable values for the poke lock code (timeout between a user activity and the 107 * going to sleep), please refer to {@link com.android.server.PowerManagerService} 108 * for additional reference. 109 * SHORT uses the short delay for the timeout (SHORT_KEYLIGHT_DELAY, 6 sec) 110 * MEDIUM uses the medium delay for the timeout (MEDIUM_KEYLIGHT_DELAY, 15 sec) 111 * DEFAULT is the system-wide default delay for the timeout (1 min) 112 */ 113 public enum ScreenTimeoutDuration { 114 SHORT, 115 MEDIUM, 116 DEFAULT 117 } 118 119 /** 120 * Allowable values for the wake lock code. 121 * SLEEP means the device can be put to sleep. 122 * PARTIAL means wake the processor, but we display can be kept off. 123 * FULL means wake both the processor and the display. 124 */ 125 public enum WakeState { 126 SLEEP, 127 PARTIAL, 128 FULL 129 } 130 131 private static PhoneApp sMe; 132 133 // A few important fields we expose to the rest of the package 134 // directly (rather than thru set/get methods) for efficiency. 135 Phone phone; 136 CallNotifier notifier; 137 Ringer ringer; 138 BluetoothHandsfree mBtHandsfree; 139 PhoneInterfaceManager phoneMgr; 140 int mBluetoothHeadsetState = BluetoothHeadset.STATE_ERROR; 141 int mBluetoothHeadsetAudioState = BluetoothHeadset.STATE_ERROR; 142 boolean mShowBluetoothIndication = false; 143 144 // Internal PhoneApp Call state tracker 145 CdmaPhoneCallState cdmaPhoneCallState; 146 147 // The InCallScreen instance (or null if the InCallScreen hasn't been 148 // created yet.) 149 private InCallScreen mInCallScreen; 150 151 // The currently-active PUK entry activity and progress dialog. 152 // Normally, these are the Emergency Dialer and the subsequent 153 // progress dialog. null if there is are no such objects in 154 // the foreground. 155 private Activity mPUKEntryActivity; 156 private ProgressDialog mPUKEntryProgressDialog; 157 158 private boolean mIsSimPinEnabled; 159 private String mCachedSimPin; 160 161 // True if a wired headset is currently plugged in, based on the state 162 // from the latest Intent.ACTION_HEADSET_PLUG broadcast we received in 163 // mReceiver.onReceive(). 164 private boolean mIsHeadsetPlugged; 165 166 private WakeState mWakeState = WakeState.SLEEP; 167 private ScreenTimeoutDuration mScreenTimeoutDuration = ScreenTimeoutDuration.DEFAULT; 168 private boolean mIgnoreTouchUserActivity = false; 169 private IBinder mPokeLockToken = new Binder(); 170 private IPowerManager mPowerManagerService; 171 private PowerManager.WakeLock mWakeLock; 172 private PowerManager.WakeLock mPartialWakeLock; 173 private KeyguardManager mKeyguardManager; 174 private KeyguardManager.KeyguardLock mKeyguardLock; 175 176 // Broadcast receiver for various intent broadcasts (see onCreate()) 177 private final BroadcastReceiver mReceiver = new PhoneAppBroadcastReceiver(); 178 179 // Broadcast receiver purely for ACTION_MEDIA_BUTTON broadcasts 180 private final BroadcastReceiver mMediaButtonReceiver = new MediaButtonBroadcastReceiver(); 181 182 /** boolean indicating restoring mute state on InCallScreen.onResume() */ 183 private boolean mShouldRestoreMuteOnInCallResume; 184 185 /** 186 * Set the restore mute state flag. Used when we are setting the mute state 187 * OUTSIDE of user interaction {@link PhoneUtils#startNewCall(Phone)} 188 */ setRestoreMuteOnInCallResume(boolean mode)189 /*package*/void setRestoreMuteOnInCallResume (boolean mode) { 190 mShouldRestoreMuteOnInCallResume = mode; 191 } 192 193 /** 194 * Get the restore mute state flag. 195 * This is used by the InCallScreen {@link InCallScreen#onResume()} to figure 196 * out if we need to restore the mute state for the current active call. 197 */ getRestoreMuteOnInCallResume()198 /*package*/boolean getRestoreMuteOnInCallResume () { 199 return mShouldRestoreMuteOnInCallResume; 200 } 201 202 Handler mHandler = new Handler() { 203 @Override 204 public void handleMessage(Message msg) { 205 switch (msg.what) { 206 case EVENT_SIM_LOCKED: 207 // mIsSimPinEnabled = true; 208 // 209 // if (Config.LOGV) Log.v(LOG_TAG, "show sim unlock panel"); 210 // SimPinUnlockPanel pinUnlockPanel = new SimPinUnlockPanel( 211 // PhoneApp.getInstance()); 212 // pinUnlockPanel.show(); 213 break; 214 215 case EVENT_SIM_ABSENT: 216 // Don't need this now that the lock screen handles this case 217 // if (Config.LOGV) Log.v(LOG_TAG, "show sim missing panel"); 218 // SimMissingPanel missingPanel = new SimMissingPanel( 219 // PhoneApp.getInstance()); 220 // missingPanel.show(); 221 break; 222 223 case EVENT_SIM_NETWORK_LOCKED: 224 if (getResources().getBoolean(R.bool.ignore_sim_network_locked_events)) { 225 // Some products don't have the concept of a "SIM network lock" 226 Log.i(LOG_TAG, "Ignoring EVENT_SIM_NETWORK_LOCKED event; " 227 + "not showing 'SIM network unlock' PIN entry screen"); 228 } else { 229 // Normal case: show the "SIM network unlock" PIN entry screen. 230 // The user won't be able to do anything else until 231 // they enter a valid SIM network PIN. 232 Log.i(LOG_TAG, "show sim depersonal panel"); 233 IccNetworkDepersonalizationPanel ndpPanel = 234 new IccNetworkDepersonalizationPanel(PhoneApp.getInstance()); 235 ndpPanel.show(); 236 } 237 break; 238 239 case EVENT_UPDATE_INCALL_NOTIFICATION: 240 // Tell the NotificationMgr to update the "ongoing 241 // call" icon in the status bar, if necessary. 242 // Currently, this is triggered by a bluetooth headset 243 // state change (since the status bar icon needs to 244 // turn blue when bluetooth is active.) 245 NotificationMgr.getDefault().updateInCallNotification(); 246 break; 247 248 case EVENT_DATA_ROAMING_DISCONNECTED: 249 NotificationMgr.getDefault().showDataDisconnectedRoaming(); 250 break; 251 252 case EVENT_DATA_ROAMING_OK: 253 NotificationMgr.getDefault().hideDataDisconnectedRoaming(); 254 break; 255 256 case MMI_COMPLETE: 257 onMMIComplete((AsyncResult) msg.obj); 258 break; 259 260 case MMI_CANCEL: 261 PhoneUtils.cancelMmiCode(phone); 262 break; 263 264 case EVENT_WIRED_HEADSET_PLUG: 265 // Since the presence of a wired headset or bluetooth affects the 266 // speakerphone, update the "speaker" state. We ONLY want to do 267 // this on the wired headset connect / disconnect events for now 268 // though, so we're only triggering on EVENT_WIRED_HEADSET_PLUG. 269 if (!isHeadsetPlugged() && 270 (mBtHandsfree == null || !mBtHandsfree.isAudioOn())) { 271 // is the state is "not connected", restore the speaker state. 272 PhoneUtils.restoreSpeakerMode(getApplicationContext()); 273 } 274 NotificationMgr.getDefault().updateSpeakerNotification(); 275 break; 276 277 case EVENT_SIM_STATE_CHANGED: 278 // Marks the event where the SIM goes into ready state. 279 // Right now, this is only used for the PUK-unlocking 280 // process. 281 if (msg.obj.equals(IccCard.INTENT_VALUE_ICC_READY)) { 282 // when the right event is triggered and there 283 // are UI objects in the foreground, we close 284 // them to display the lock panel. 285 if (mPUKEntryActivity != null) { 286 mPUKEntryActivity.finish(); 287 mPUKEntryActivity = null; 288 } 289 if (mPUKEntryProgressDialog != null) { 290 mPUKEntryProgressDialog.dismiss(); 291 mPUKEntryProgressDialog = null; 292 } 293 } 294 break; 295 296 case EVENT_UNSOL_CDMA_INFO_RECORD: 297 //TODO: handle message here; 298 break; 299 } 300 } 301 }; 302 PhoneApp()303 public PhoneApp() { 304 sMe = this; 305 } 306 307 @Override onCreate()308 public void onCreate() { 309 if (Config.LOGV) Log.v(LOG_TAG, "onCreate()..."); 310 311 ContentResolver resolver = getContentResolver(); 312 313 if (phone == null) { 314 // Initialize the telephony framework 315 PhoneFactory.makeDefaultPhones(this); 316 317 // Get the default phone 318 phone = PhoneFactory.getDefaultPhone(); 319 320 NotificationMgr.init(this); 321 322 phoneMgr = new PhoneInterfaceManager(this, phone); 323 if (getSystemService(Context.BLUETOOTH_SERVICE) != null) { 324 mBtHandsfree = new BluetoothHandsfree(this, phone); 325 startService(new Intent(this, BluetoothHeadsetService.class)); 326 } else { 327 // Device is not bluetooth capable 328 mBtHandsfree = null; 329 } 330 331 ringer = new Ringer(phone); 332 333 // before registering for phone state changes 334 PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE); 335 mWakeLock = pm.newWakeLock(PowerManager.FULL_WAKE_LOCK 336 | PowerManager.ACQUIRE_CAUSES_WAKEUP 337 | PowerManager.ON_AFTER_RELEASE, LOG_TAG); 338 // lock used to keep the processor awake, when we don't care for the display. 339 mPartialWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK 340 | PowerManager.ON_AFTER_RELEASE, LOG_TAG); 341 mKeyguardManager = (KeyguardManager) getSystemService(Context.KEYGUARD_SERVICE); 342 mKeyguardLock = mKeyguardManager.newKeyguardLock(LOG_TAG); 343 344 // get a handle to the service so that we can use it later when we 345 // want to set the poke lock. 346 mPowerManagerService = IPowerManager.Stub.asInterface( 347 ServiceManager.getService("power")); 348 349 notifier = new CallNotifier(this, phone, ringer, mBtHandsfree); 350 351 // register for ICC status 352 IccCard sim = phone.getIccCard(); 353 if (sim != null) { 354 if (Config.LOGV) Log.v(LOG_TAG, "register for ICC status"); 355 sim.registerForAbsent(mHandler, EVENT_SIM_ABSENT, null); 356 sim.registerForLocked(mHandler, EVENT_SIM_LOCKED, null); 357 sim.registerForNetworkLocked(mHandler, EVENT_SIM_NETWORK_LOCKED, null); 358 } 359 360 // register for MMI/USSD 361 phone.registerForMmiComplete(mHandler, MMI_COMPLETE, null); 362 363 // register connection tracking to PhoneUtils 364 PhoneUtils.initializeConnectionHandler(phone); 365 366 // Register for misc other intent broadcasts. 367 IntentFilter intentFilter = 368 new IntentFilter(Intent.ACTION_AIRPLANE_MODE_CHANGED); 369 intentFilter.addAction(BluetoothIntent.HEADSET_STATE_CHANGED_ACTION); 370 intentFilter.addAction(BluetoothIntent.HEADSET_AUDIO_STATE_CHANGED_ACTION); 371 intentFilter.addAction(TelephonyIntents.ACTION_ANY_DATA_CONNECTION_STATE_CHANGED); 372 intentFilter.addAction(Intent.ACTION_HEADSET_PLUG); 373 intentFilter.addAction(Intent.ACTION_BATTERY_LOW); 374 intentFilter.addAction(TelephonyIntents.ACTION_SIM_STATE_CHANGED); 375 intentFilter.addAction(TelephonyIntents.ACTION_RADIO_TECHNOLOGY_CHANGED); 376 intentFilter.addAction(TelephonyIntents.ACTION_SERVICE_STATE_CHANGED); 377 intentFilter.addAction(TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED); 378 registerReceiver(mReceiver, intentFilter); 379 380 // Use a separate receiver for ACTION_MEDIA_BUTTON broadcasts, 381 // since we need to manually adjust its priority (to make sure 382 // we get these intents *before* the media player.) 383 IntentFilter mediaButtonIntentFilter = 384 new IntentFilter(Intent.ACTION_MEDIA_BUTTON); 385 // 386 // Make sure we're higher priority than the media player's 387 // MediaButtonIntentReceiver (which currently has the default 388 // priority of zero; see apps/Music/AndroidManifest.xml.) 389 mediaButtonIntentFilter.setPriority(1); 390 // 391 registerReceiver(mMediaButtonReceiver, mediaButtonIntentFilter); 392 393 //set the default values for the preferences in the phone. 394 PreferenceManager.setDefaultValues(this, R.xml.network_setting, false); 395 PreferenceManager.setDefaultValues(this, R.xml.call_feature_setting, false); 396 397 // Make sure the audio mode (along with some 398 // audio-mode-related state of our own) is initialized 399 // correctly, given the current state of the phone. 400 switch (phone.getState()) { 401 case IDLE: 402 if (DBG) Log.d(LOG_TAG, "Resetting audio state/mode: IDLE"); 403 PhoneUtils.setAudioControlState(PhoneUtils.AUDIO_IDLE); 404 PhoneUtils.setAudioMode(this, AudioManager.MODE_NORMAL); 405 break; 406 case RINGING: 407 if (DBG) Log.d(LOG_TAG, "Resetting audio state/mode: RINGING"); 408 PhoneUtils.setAudioControlState(PhoneUtils.AUDIO_RINGING); 409 PhoneUtils.setAudioMode(this, AudioManager.MODE_RINGTONE); 410 break; 411 case OFFHOOK: 412 if (DBG) Log.d(LOG_TAG, "Resetting audio state/mode: OFFHOOK"); 413 PhoneUtils.setAudioControlState(PhoneUtils.AUDIO_OFFHOOK); 414 PhoneUtils.setAudioMode(this, AudioManager.MODE_IN_CALL); 415 break; 416 } 417 } 418 419 // XXX pre-load the SimProvider so that it's ready 420 resolver.getType(Uri.parse("content://icc/adn")); 421 422 // start with the default value to set the mute state. 423 mShouldRestoreMuteOnInCallResume = false; 424 425 // Register for Cdma Information Records 426 // TODO(Moto): Merge 427 // phone.registerCdmaInformationRecord(mHandler, EVENT_UNSOL_CDMA_INFO_RECORD, null); 428 429 if (phone.getPhoneName().equals("CDMA")) { 430 // Create an instance of CdmaPhoneCallState and initialize it to IDLE 431 cdmaPhoneCallState = new CdmaPhoneCallState(); 432 cdmaPhoneCallState.CdmaPhoneCallStateInit(); 433 } 434 } 435 436 /** 437 * Returns the singleton instance of the PhoneApp. 438 */ getInstance()439 static PhoneApp getInstance() { 440 return sMe; 441 } 442 getRinger()443 Ringer getRinger() { 444 return ringer; 445 } 446 getBluetoothHandsfree()447 BluetoothHandsfree getBluetoothHandsfree() { 448 return mBtHandsfree; 449 } 450 createCallLogIntent()451 static Intent createCallLogIntent() { 452 Intent intent = new Intent(Intent.ACTION_VIEW, null); 453 intent.setType("vnd.android.cursor.dir/calls"); 454 return intent; 455 } 456 457 /** 458 * Return an Intent that can be used to bring up the in-call screen. 459 * 460 * This intent can only be used from within the Phone app, since the 461 * InCallScreen is not exported from our AndroidManifest. 462 */ createInCallIntent()463 /* package */ static Intent createInCallIntent() { 464 Intent intent = new Intent(Intent.ACTION_MAIN, null); 465 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK 466 | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS 467 | Intent.FLAG_ACTIVITY_NO_USER_ACTION); 468 intent.setClassName("com.android.phone", getCallScreenClassName()); 469 return intent; 470 } 471 472 /** 473 * Variation of createInCallIntent() that also specifies whether the 474 * DTMF dialpad should be initially visible when the InCallScreen 475 * comes up. 476 */ createInCallIntent(boolean showDialpad)477 /* package */ static Intent createInCallIntent(boolean showDialpad) { 478 Intent intent = createInCallIntent(); 479 intent.putExtra(InCallScreen.SHOW_DIALPAD_EXTRA, showDialpad); 480 return intent; 481 } 482 getCallScreenClassName()483 static String getCallScreenClassName() { 484 return InCallScreen.class.getName(); 485 } 486 487 /** 488 * Starts the InCallScreen Activity. 489 */ displayCallScreen()490 void displayCallScreen() { 491 if (VDBG) Log.d(LOG_TAG, "displayCallScreen()..."); 492 startActivity(createInCallIntent()); 493 Profiler.callScreenRequested(); 494 } 495 496 /** 497 * Helper function to check for one special feature of the CALL key: 498 * Normally, when the phone is idle, CALL takes you to the call log 499 * (see the handler for KEYCODE_CALL in PhoneWindow.onKeyUp().) 500 * But if the phone is in use (either off-hook or ringing) we instead 501 * handle the CALL button by taking you to the in-call UI. 502 * 503 * @return true if we intercepted the CALL keypress (i.e. the phone 504 * was in use) 505 * 506 * @see DialerActivity#onCreate 507 */ handleInCallOrRinging()508 boolean handleInCallOrRinging() { 509 if (phone.getState() != Phone.State.IDLE) { 510 // Phone is OFFHOOK or RINGING. 511 if (DBG) Log.v(LOG_TAG, 512 "handleInCallOrRinging: show call screen"); 513 displayCallScreen(); 514 return true; 515 } 516 return false; 517 } 518 isSimPinEnabled()519 boolean isSimPinEnabled() { 520 return mIsSimPinEnabled; 521 } 522 authenticateAgainstCachedSimPin(String pin)523 boolean authenticateAgainstCachedSimPin(String pin) { 524 return (mCachedSimPin != null && mCachedSimPin.equals(pin)); 525 } 526 setCachedSimPin(String pin)527 void setCachedSimPin(String pin) { 528 mCachedSimPin = pin; 529 } 530 setInCallScreenInstance(InCallScreen inCallScreen)531 void setInCallScreenInstance(InCallScreen inCallScreen) { 532 mInCallScreen = inCallScreen; 533 } 534 535 /** 536 * @return true if the in-call UI is running as the foreground 537 * activity. (In other words, from the perspective of the 538 * InCallScreen activity, return true between onResume() and 539 * onPause().) 540 * 541 * Note this method will return false if the screen is currently off, 542 * even if the InCallScreen *was* in the foreground just before the 543 * screen turned off. (This is because the foreground activity is 544 * always "paused" while the screen is off.) 545 */ isShowingCallScreen()546 boolean isShowingCallScreen() { 547 if (mInCallScreen == null) return false; 548 return mInCallScreen.isForegroundActivity(); 549 } 550 551 /** 552 * Dismisses the in-call UI. 553 * 554 * This also ensures that you won't be able to get back to the in-call 555 * UI via the BACK button (since this call removes the InCallScreen 556 * from the activity history.) 557 */ dismissCallScreen()558 void dismissCallScreen() { 559 if (mInCallScreen != null) { 560 mInCallScreen.finish(); 561 } 562 } 563 564 /** 565 * Sets the activity responsible for un-PUK-blocking the device 566 * so that we may close it when we receive a positive result. 567 * mPUKEntryActivity is also used to indicate to the device that 568 * we are trying to un-PUK-lock the phone. In other words, iff 569 * it is NOT null, then we are trying to unlock and waiting for 570 * the SIM to move to READY state. 571 * 572 * @param activity is the activity to close when PUK has 573 * finished unlocking. Can be set to null to indicate the unlock 574 * or SIM READYing process is over. 575 */ setPukEntryActivity(Activity activity)576 void setPukEntryActivity(Activity activity) { 577 mPUKEntryActivity = activity; 578 } 579 getPUKEntryActivity()580 Activity getPUKEntryActivity() { 581 return mPUKEntryActivity; 582 } 583 584 /** 585 * Sets the dialog responsible for notifying the user of un-PUK- 586 * blocking - SIM READYing progress, so that we may dismiss it 587 * when we receive a positive result. 588 * 589 * @param dialog indicates the progress dialog informing the user 590 * of the state of the device. Dismissed upon completion of 591 * READYing process 592 */ setPukEntryProgressDialog(ProgressDialog dialog)593 void setPukEntryProgressDialog(ProgressDialog dialog) { 594 mPUKEntryProgressDialog = dialog; 595 } 596 getPUKEntryProgressDialog()597 ProgressDialog getPUKEntryProgressDialog() { 598 return mPUKEntryProgressDialog; 599 } 600 601 /** 602 * Disables the keyguard. This is used by the phone app to allow 603 * interaction with the Phone UI when the keyguard would otherwise be 604 * active (like receiving an incoming call while the device is 605 * locked.) 606 * 607 * Any call to this method MUST be followed (eventually) 608 * by a corresponding reenableKeyguard() call. 609 */ disableKeyguard()610 /* package */ void disableKeyguard() { 611 if (DBG) Log.d(LOG_TAG, "disable keyguard"); 612 // if (DBG) Log.d(LOG_TAG, "disableKeyguard()...", new Throwable("stack dump")); 613 mKeyguardLock.disableKeyguard(); 614 } 615 616 /** 617 * Re-enables the keyguard after a previous disableKeyguard() call. 618 * 619 * Any call to this method MUST correspond to (i.e. be balanced with) 620 * a previous disableKeyguard() call. 621 */ reenableKeyguard()622 /* package */ void reenableKeyguard() { 623 if (DBG) Log.d(LOG_TAG, "re-enable keyguard"); 624 // if (DBG) Log.d(LOG_TAG, "reenableKeyguard()...", new Throwable("stack dump")); 625 mKeyguardLock.reenableKeyguard(); 626 } 627 628 /** 629 * Controls how quickly the screen times out. 630 * 631 * The poke lock controls how long it takes before the screen powers 632 * down, and therefore has no immediate effect when the current 633 * WakeState (see {@link PhoneApp#requestWakeState}) is FULL. 634 * If we're in a state where the screen *is* allowed to turn off, 635 * though, the poke lock will determine the timeout interval (long or 636 * short). 637 * 638 * @param shortPokeLock tells the device the timeout duration to use 639 * before going to sleep 640 * {@link com.android.server.PowerManagerService#SHORT_KEYLIGHT_DELAY}. 641 */ setScreenTimeout(ScreenTimeoutDuration duration)642 /* package */ void setScreenTimeout(ScreenTimeoutDuration duration) { 643 if (VDBG) Log.d(LOG_TAG, "setScreenTimeout(" + duration + ")..."); 644 645 // make sure we don't set the poke lock repeatedly so that we 646 // avoid triggering the userActivity calls in 647 // PowerManagerService.setPokeLock(). 648 if (duration == mScreenTimeoutDuration) { 649 return; 650 } 651 mScreenTimeoutDuration = duration; 652 updatePokeLock(); 653 } 654 655 /** 656 * Update the state of the poke lock held by the phone app, 657 * based on the current desired screen timeout and the 658 * current "ignore user activity on touch" flag. 659 */ updatePokeLock()660 private void updatePokeLock() { 661 // This is kind of convoluted, but the basic thing to remember is 662 // that the poke lock just sends a message to the screen to tell 663 // it to stay on for a while. 664 // The default is 0, for a long timeout and should be set that way 665 // when we are heading back into a the keyguard / screen off 666 // state, and also when we're trying to keep the screen alive 667 // while ringing. We'll also want to ignore the cheek events 668 // regardless of the timeout duration. 669 // The short timeout is really used whenever we want to give up 670 // the screen lock, such as when we're in call. 671 int pokeLockSetting = LocalPowerManager.POKE_LOCK_IGNORE_CHEEK_EVENTS; 672 switch (mScreenTimeoutDuration) { 673 case SHORT: 674 // Set the poke lock to timeout the display after a short 675 // timeout (5s). This ensures that the screen goes to sleep 676 // as soon as acceptably possible after we the wake lock 677 // has been released. 678 pokeLockSetting |= LocalPowerManager.POKE_LOCK_SHORT_TIMEOUT; 679 break; 680 681 case MEDIUM: 682 // Set the poke lock to timeout the display after a medium 683 // timeout (15s). This ensures that the screen goes to sleep 684 // as soon as acceptably possible after we the wake lock 685 // has been released. 686 pokeLockSetting |= LocalPowerManager.POKE_LOCK_MEDIUM_TIMEOUT; 687 break; 688 689 case DEFAULT: 690 default: 691 // set the poke lock to timeout the display after a long 692 // delay by default. 693 // TODO: it may be nice to be able to disable cheek presses 694 // for long poke locks (emergency dialer, for instance). 695 break; 696 } 697 698 if (mIgnoreTouchUserActivity) { 699 pokeLockSetting |= LocalPowerManager.POKE_LOCK_IGNORE_TOUCH_AND_CHEEK_EVENTS; 700 } 701 702 // Send the request 703 try { 704 mPowerManagerService.setPokeLock(pokeLockSetting, mPokeLockToken, LOG_TAG); 705 } catch (RemoteException e) { 706 Log.w(LOG_TAG, "mPowerManagerService.setPokeLock() failed: " + e); 707 } 708 } 709 710 /** 711 * Controls whether or not the screen is allowed to sleep. 712 * 713 * Once sleep is allowed (WakeState is SLEEP), it will rely on the 714 * settings for the poke lock to determine when to timeout and let 715 * the device sleep {@link PhoneApp#setScreenTimeout}. 716 * 717 * @param ws tells the device to how to wake. 718 */ requestWakeState(WakeState ws)719 /* package */ void requestWakeState(WakeState ws) { 720 if (VDBG) Log.d(LOG_TAG, "requestWakeState(" + ws + ")..."); 721 if (mWakeState != ws) { 722 switch (ws) { 723 case PARTIAL: 724 // acquire the processor wake lock, and release the FULL 725 // lock if it is being held. 726 mPartialWakeLock.acquire(); 727 if (mWakeLock.isHeld()) { 728 mWakeLock.release(); 729 } 730 break; 731 case FULL: 732 // acquire the full wake lock, and release the PARTIAL 733 // lock if it is being held. 734 mWakeLock.acquire(); 735 if (mPartialWakeLock.isHeld()) { 736 mPartialWakeLock.release(); 737 } 738 break; 739 case SLEEP: 740 default: 741 // release both the PARTIAL and FULL locks. 742 if (mWakeLock.isHeld()) { 743 mWakeLock.release(); 744 } 745 if (mPartialWakeLock.isHeld()) { 746 mPartialWakeLock.release(); 747 } 748 break; 749 } 750 mWakeState = ws; 751 } 752 } 753 754 /** 755 * If we are not currently keeping the screen on, then poke the power 756 * manager to wake up the screen for the user activity timeout duration. 757 */ wakeUpScreen()758 /* package */ void wakeUpScreen() { 759 if (mWakeState == WakeState.SLEEP) { 760 if (DBG) Log.d(LOG_TAG, "pulse screen lock"); 761 try { 762 mPowerManagerService.userActivityWithForce(SystemClock.uptimeMillis(), false, true); 763 } catch (RemoteException ex) { 764 // Ignore -- the system process is dead. 765 } 766 } 767 } 768 769 /** 770 * Sets the wake state and screen timeout based on the current state 771 * of the phone, and the current state of the in-call UI. 772 * 773 * This method is a "UI Policy" wrapper around 774 * {@link PhoneApp#requestWakeState} and {@link PhoneApp#setScreenTimeout}. 775 * 776 * It's safe to call this method regardless of the state of the Phone 777 * (e.g. whether or not it's idle), and regardless of the state of the 778 * Phone UI (e.g. whether or not the InCallScreen is active.) 779 */ updateWakeState()780 /* package */ void updateWakeState() { 781 Phone.State state = phone.getState(); 782 783 // True if the in-call UI is the foreground activity. 784 // (Note this will be false if the screen is currently off, 785 // since in that case *no* activity is in the foreground.) 786 boolean isShowingCallScreen = isShowingCallScreen(); 787 788 // True if the InCallScreen's DTMF dialer is currently opened. 789 // (Note this does NOT imply whether or not the InCallScreen 790 // itself is visible.) 791 boolean isDialerOpened = (mInCallScreen != null) && mInCallScreen.isDialerOpened(); 792 793 // True if the speakerphone is in use. (If so, we *always* use 794 // the default timeout. Since the user is obviously not holding 795 // the phone up to his/her face, we don't need to worry about 796 // false touches, and thus don't need to turn the screen off so 797 // aggressively.) 798 // Note that we need to make a fresh call to this method any 799 // time the speaker state changes. (That happens in 800 // PhoneUtils.turnOnSpeaker().) 801 boolean isSpeakerInUse = (state == Phone.State.OFFHOOK) && PhoneUtils.isSpeakerOn(this); 802 803 // TODO (bug 1440854): The screen timeout *might* also need to 804 // depend on the bluetooth state, but this isn't as clear-cut as 805 // the speaker state (since while using BT it's common for the 806 // user to put the phone straight into a pocket, in which case the 807 // timeout should probably still be short.) 808 809 if (DBG) Log.d(LOG_TAG, "updateWakeState: callscreen " + isShowingCallScreen 810 + ", dialer " + isDialerOpened 811 + ", speaker " + isSpeakerInUse + "..."); 812 813 // 814 // (1) Set the screen timeout. 815 // 816 // Note that the "screen timeout" value we determine here is 817 // meaningless if the screen is forced on (see (2) below.) 818 // 819 if (!isShowingCallScreen || isSpeakerInUse) { 820 // Use the system-wide default timeout. 821 setScreenTimeout(ScreenTimeoutDuration.DEFAULT); 822 } else { 823 // We're on the in-call screen, and *not* using the speakerphone. 824 if (isDialerOpened) { 825 // The DTMF dialpad is up. This case is special because 826 // the in-call UI has its own "touch lock" mechanism to 827 // disable the dialpad after a very short amount of idle 828 // time (to avoid false touches from the user's face while 829 // in-call.) 830 // 831 // In this case the *physical* screen just uses the 832 // system-wide default timeout. 833 setScreenTimeout(ScreenTimeoutDuration.DEFAULT); 834 } else { 835 // We're on the in-call screen, and not using the DTMF dialpad. 836 // There's actually no touchable UI onscreen at all in 837 // this state. Also, the user is (most likely) not 838 // looking at the screen at all, since they're probably 839 // holding the phone up to their face. Here we use a 840 // special screen timeout value specific to the in-call 841 // screen, purely to save battery life. 842 setScreenTimeout(ScreenTimeoutDuration.MEDIUM); 843 } 844 } 845 846 // 847 // (2) Decide whether to force the screen on or not. 848 // 849 // Force the screen to be on if the phone is ringing, or if we're 850 // displaying the "Call ended" UI for a connection in the 851 // "disconnected" state. 852 // 853 boolean isRinging = (state == Phone.State.RINGING); 854 boolean showingDisconnectedConnection = 855 PhoneUtils.hasDisconnectedConnections(phone) && isShowingCallScreen; 856 boolean keepScreenOn = isRinging || showingDisconnectedConnection; 857 if (DBG) Log.d(LOG_TAG, "updateWakeState: keepScreenOn = " + keepScreenOn 858 + " (isRinging " + isRinging 859 + ", showingDisc " + showingDisconnectedConnection + ")"); 860 // keepScreenOn == true means we'll hold a full wake lock: 861 requestWakeState(keepScreenOn ? WakeState.FULL : WakeState.SLEEP); 862 } 863 864 /** 865 * Wrapper around the PowerManagerService.preventScreenOn() API. 866 * This allows the in-call UI to prevent the screen from turning on 867 * even if a subsequent call to updateWakeState() causes us to acquire 868 * a full wake lock. 869 */ preventScreenOn(boolean prevent)870 /* package */ void preventScreenOn(boolean prevent) { 871 if (VDBG) Log.d(LOG_TAG, "- preventScreenOn(" + prevent + ")..."); 872 try { 873 mPowerManagerService.preventScreenOn(prevent); 874 } catch (RemoteException e) { 875 Log.w(LOG_TAG, "mPowerManagerService.preventScreenOn() failed: " + e); 876 } 877 } 878 879 /** 880 * Sets or clears the flag that tells the PowerManager that touch 881 * (and cheek) events should NOT be considered "user activity". 882 * 883 * Since the in-call UI is totally insensitive to touch in most 884 * states, we set this flag whenever the InCallScreen is in the 885 * foreground. (Otherwise, repeated unintentional touches could 886 * prevent the device from going to sleep.) 887 * 888 * There *are* some some touch events that really do count as user 889 * activity, though. For those, we need to manually poke the 890 * PowerManager's userActivity method; see pokeUserActivity(). 891 */ setIgnoreTouchUserActivity(boolean ignore)892 /* package */ void setIgnoreTouchUserActivity(boolean ignore) { 893 if (VDBG) Log.d(LOG_TAG, "setIgnoreTouchUserActivity(" + ignore + ")..."); 894 mIgnoreTouchUserActivity = ignore; 895 updatePokeLock(); 896 } 897 898 /** 899 * Manually pokes the PowerManager's userActivity method. Since we 900 * hold the POKE_LOCK_IGNORE_TOUCH_AND_CHEEK_EVENTS poke lock while 901 * the InCallScreen is active, we need to do this for touch events 902 * that really do count as user activity (like DTMF key presses, or 903 * unlocking the "touch lock" overlay.) 904 */ pokeUserActivity()905 /* package */ void pokeUserActivity() { 906 if (VDBG) Log.d(LOG_TAG, "pokeUserActivity()..."); 907 try { 908 mPowerManagerService.userActivity(SystemClock.uptimeMillis(), false); 909 } catch (RemoteException e) { 910 Log.w(LOG_TAG, "mPowerManagerService.userActivity() failed: " + e); 911 } 912 } 913 getKeyguardManager()914 KeyguardManager getKeyguardManager() { 915 return mKeyguardManager; 916 } 917 onMMIComplete(AsyncResult r)918 private void onMMIComplete(AsyncResult r) { 919 if (VDBG) Log.d(LOG_TAG, "onMMIComplete()..."); 920 MmiCode mmiCode = (MmiCode) r.result; 921 PhoneUtils.displayMMIComplete(phone, getInstance(), mmiCode, null, null); 922 } 923 initForNewRadioTechnology()924 private void initForNewRadioTechnology() { 925 if (DBG) Log.d(LOG_TAG, "initForNewRadioTechnology..."); 926 927 ringer.updateRingerContextAfterRadioTechnologyChange(this.phone); 928 notifier.updateCallNotifierRegistrationsAfterRadioTechnologyChange(); 929 if (mBtHandsfree != null) { 930 mBtHandsfree.updateBtHandsfreeAfterRadioTechnologyChange(); 931 } 932 if (mInCallScreen != null) { 933 mInCallScreen.updateAfterRadioTechnologyChange(); 934 } 935 936 // Update registration for ICC status after radio technology change 937 IccCard sim = phone.getIccCard(); 938 if (sim != null) { 939 if (DBG) Log.d(LOG_TAG, "Update registration for ICC status..."); 940 941 //Register all events new to the new active phone 942 sim.registerForAbsent(mHandler, EVENT_SIM_ABSENT, null); 943 sim.registerForLocked(mHandler, EVENT_SIM_LOCKED, null); 944 sim.registerForNetworkLocked(mHandler, EVENT_SIM_NETWORK_LOCKED, null); 945 } 946 947 if (phone.getPhoneName().equals("CDMA")) { 948 // Create an instance of CdmaPhoneCallState and initialize it to IDLE 949 cdmaPhoneCallState = new CdmaPhoneCallState(); 950 cdmaPhoneCallState.CdmaPhoneCallStateInit(); 951 } 952 } 953 954 955 /** 956 * Send ECBM Exit Request 957 */ 958 sendEcbmExitRequest()959 void sendEcbmExitRequest() { 960 mHandler.sendEmptyMessage(EVENT_UPDATE_INCALL_NOTIFICATION); 961 } 962 963 /** 964 * @return true if a wired headset is currently plugged in. 965 * 966 * @see Intent.ACTION_HEADSET_PLUG (which we listen for in mReceiver.onReceive()) 967 */ isHeadsetPlugged()968 boolean isHeadsetPlugged() { 969 return mIsHeadsetPlugged; 970 } 971 972 /** 973 * @return true if the onscreen UI should currently be showing the 974 * special "bluetooth is active" indication in a couple of places (in 975 * which UI elements turn blue and/or show the bluetooth logo.) 976 * 977 * This depends on the BluetoothHeadset state *and* the current 978 * telephony state; see shouldShowBluetoothIndication(). 979 * 980 * @see CallCard 981 * @see NotificationMgr.updateInCallNotification 982 */ showBluetoothIndication()983 /* package */ boolean showBluetoothIndication() { 984 return mShowBluetoothIndication; 985 } 986 987 /** 988 * Recomputes the mShowBluetoothIndication flag based on the current 989 * bluetooth state and current telephony state. 990 * 991 * This needs to be called any time the bluetooth headset state or the 992 * telephony state changes. 993 * 994 * @param forceUiUpdate if true, force the UI elements that care 995 * about this flag to update themselves. 996 */ updateBluetoothIndication(boolean forceUiUpdate)997 /* package */ void updateBluetoothIndication(boolean forceUiUpdate) { 998 mShowBluetoothIndication = shouldShowBluetoothIndication(mBluetoothHeadsetState, 999 mBluetoothHeadsetAudioState, 1000 phone); 1001 if (forceUiUpdate) { 1002 // Post Handler messages to the various components that might 1003 // need to be refreshed based on the new state. 1004 if (isShowingCallScreen()) mInCallScreen.updateBluetoothIndication(); 1005 mHandler.sendEmptyMessage(EVENT_UPDATE_INCALL_NOTIFICATION); 1006 } 1007 } 1008 1009 /** 1010 * UI policy helper function for the couple of places in the UI that 1011 * have some way of indicating that "bluetooth is in use." 1012 * 1013 * @return true if the onscreen UI should indicate that "bluetooth is in use", 1014 * based on the specified bluetooth headset state, and the 1015 * current state of the phone. 1016 * @see showBluetoothIndication() 1017 */ shouldShowBluetoothIndication(int bluetoothState, int bluetoothAudioState, Phone phone)1018 private static boolean shouldShowBluetoothIndication(int bluetoothState, 1019 int bluetoothAudioState, 1020 Phone phone) { 1021 // We want the UI to indicate that "bluetooth is in use" in two 1022 // slightly different cases: 1023 // 1024 // (a) The obvious case: if a bluetooth headset is currently in 1025 // use for an ongoing call. 1026 // 1027 // (b) The not-so-obvious case: if an incoming call is ringing, 1028 // and we expect that audio *will* be routed to a bluetooth 1029 // headset once the call is answered. 1030 1031 switch (phone.getState()) { 1032 case OFFHOOK: 1033 // This covers normal active calls, and also the case if 1034 // the foreground call is DIALING or ALERTING. In this 1035 // case, bluetooth is considered "active" if a headset 1036 // is connected *and* audio is being routed to it. 1037 return ((bluetoothState == BluetoothHeadset.STATE_CONNECTED) 1038 && (bluetoothAudioState == BluetoothHeadset.AUDIO_STATE_CONNECTED)); 1039 1040 case RINGING: 1041 // If an incoming call is ringing, we're *not* yet routing 1042 // audio to the headset (since there's no in-call audio 1043 // yet!) In this case, if a bluetooth headset is 1044 // connected at all, we assume that it'll become active 1045 // once the user answers the phone. 1046 return (bluetoothState == BluetoothHeadset.STATE_CONNECTED); 1047 1048 default: // Presumably IDLE 1049 return false; 1050 } 1051 } 1052 1053 1054 /** 1055 * Receiver for misc intent broadcasts the Phone app cares about. 1056 */ 1057 private class PhoneAppBroadcastReceiver extends BroadcastReceiver { 1058 @Override onReceive(Context context, Intent intent)1059 public void onReceive(Context context, Intent intent) { 1060 String action = intent.getAction(); 1061 if (action.equals(Intent.ACTION_AIRPLANE_MODE_CHANGED)) { 1062 boolean enabled = System.getInt(getContentResolver(), 1063 System.AIRPLANE_MODE_ON, 0) == 0; 1064 phone.setRadioPower(enabled); 1065 } else if (action.equals(BluetoothIntent.HEADSET_STATE_CHANGED_ACTION)) { 1066 mBluetoothHeadsetState = intent.getIntExtra(BluetoothIntent.HEADSET_STATE, 1067 BluetoothHeadset.STATE_ERROR); 1068 if (VDBG) Log.d(LOG_TAG, "mReceiver: HEADSET_STATE_CHANGED_ACTION"); 1069 if (VDBG) Log.d(LOG_TAG, "==> new state: " + mBluetoothHeadsetState); 1070 updateBluetoothIndication(true); // Also update any visible UI if necessary 1071 } else if (action.equals(BluetoothIntent.HEADSET_AUDIO_STATE_CHANGED_ACTION)) { 1072 mBluetoothHeadsetAudioState = 1073 intent.getIntExtra(BluetoothIntent.HEADSET_AUDIO_STATE, 1074 BluetoothHeadset.STATE_ERROR); 1075 if (VDBG) Log.d(LOG_TAG, "mReceiver: HEADSET_AUDIO_STATE_CHANGED_ACTION"); 1076 if (VDBG) Log.d(LOG_TAG, "==> new state: " + mBluetoothHeadsetAudioState); 1077 updateBluetoothIndication(true); // Also update any visible UI if necessary 1078 } else if (action.equals(TelephonyIntents.ACTION_ANY_DATA_CONNECTION_STATE_CHANGED)) { 1079 if (VDBG) Log.d(LOG_TAG, "mReceiver: ACTION_ANY_DATA_CONNECTION_STATE_CHANGED"); 1080 if (VDBG) Log.d(LOG_TAG, "- state: " + intent.getStringExtra(Phone.STATE_KEY)); 1081 if (VDBG) Log.d(LOG_TAG, "- reason: " 1082 + intent.getStringExtra(Phone.STATE_CHANGE_REASON_KEY)); 1083 1084 // The "data disconnected due to roaming" notification is 1085 // visible if you've lost data connectivity because you're 1086 // roaming and you have the "data roaming" feature turned off. 1087 boolean disconnectedDueToRoaming = false; 1088 if ("DISCONNECTED".equals(intent.getStringExtra(Phone.STATE_KEY))) { 1089 String reason = intent.getStringExtra(Phone.STATE_CHANGE_REASON_KEY); 1090 if (Phone.REASON_ROAMING_ON.equals(reason)) { 1091 // We just lost our data connection, and the reason 1092 // is that we started roaming. This implies that 1093 // the user has data roaming turned off. 1094 disconnectedDueToRoaming = true; 1095 } 1096 } 1097 mHandler.sendEmptyMessage(disconnectedDueToRoaming 1098 ? EVENT_DATA_ROAMING_DISCONNECTED 1099 : EVENT_DATA_ROAMING_OK); 1100 } else if (action.equals(Intent.ACTION_HEADSET_PLUG)) { 1101 if (VDBG) Log.d(LOG_TAG, "mReceiver: ACTION_HEADSET_PLUG"); 1102 if (VDBG) Log.d(LOG_TAG, " state: " + intent.getIntExtra("state", 0)); 1103 if (VDBG) Log.d(LOG_TAG, " name: " + intent.getStringExtra("name")); 1104 mIsHeadsetPlugged = (intent.getIntExtra("state", 0) == 1); 1105 mHandler.sendMessage(mHandler.obtainMessage(EVENT_WIRED_HEADSET_PLUG, 0)); 1106 } else if (action.equals(Intent.ACTION_BATTERY_LOW)) { 1107 if (VDBG) Log.d(LOG_TAG, "mReceiver: ACTION_BATTERY_LOW"); 1108 notifier.sendBatteryLow(); // Play a warning tone if in-call 1109 } else if ((action.equals(TelephonyIntents.ACTION_SIM_STATE_CHANGED)) && 1110 (mPUKEntryActivity != null)) { 1111 // if an attempt to un-PUK-lock the device was made, while we're 1112 // receiving this state change notification, notify the handler. 1113 // NOTE: This is ONLY triggered if an attempt to un-PUK-lock has 1114 // been attempted. 1115 mHandler.sendMessage(mHandler.obtainMessage(EVENT_SIM_STATE_CHANGED, 1116 intent.getStringExtra(IccCard.INTENT_KEY_ICC_STATE))); 1117 } else if (action.equals(TelephonyIntents.ACTION_RADIO_TECHNOLOGY_CHANGED)) { 1118 String newPhone = intent.getStringExtra(Phone.PHONE_NAME_KEY); 1119 Log.d(LOG_TAG, "Radio technology switched. Now " + newPhone + " is active."); 1120 initForNewRadioTechnology(); 1121 } else if (action.equals(TelephonyIntents.ACTION_SERVICE_STATE_CHANGED)) { 1122 handleServiceStateChanged(intent); 1123 } else if (action.equals(TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED)) { 1124 Log.d(LOG_TAG, "Emergency Callback Mode arrived in PhoneApp."); 1125 // Send Intend to start ECBM application 1126 Intent EcbmAlarm = new Intent(Intent.ACTION_MAIN, null); 1127 EcbmAlarm.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 1128 EcbmAlarm.setClassName("com.android.phone", EmergencyCallbackMode.class.getName()); 1129 startActivity(EcbmAlarm); 1130 } 1131 } 1132 } 1133 1134 /** 1135 * Broadcast receiver for the ACTION_MEDIA_BUTTON broadcast intent. 1136 * 1137 * This functionality isn't lumped in with the other intents in 1138 * PhoneAppBroadcastReceiver because we instantiate this as a totally 1139 * separate BroadcastReceiver instance, since we need to manually 1140 * adjust its IntentFilter's priority (to make sure we get these 1141 * intents *before* the media player.) 1142 */ 1143 private class MediaButtonBroadcastReceiver extends BroadcastReceiver { 1144 @Override onReceive(Context context, Intent intent)1145 public void onReceive(Context context, Intent intent) { 1146 KeyEvent event = (KeyEvent) intent.getParcelableExtra(Intent.EXTRA_KEY_EVENT); 1147 if (VDBG) Log.d(LOG_TAG, 1148 "MediaButtonBroadcastReceiver.onReceive()... event = " + event); 1149 if ((event != null) 1150 && (event.getKeyCode() == KeyEvent.KEYCODE_HEADSETHOOK) 1151 && (event.getAction() == KeyEvent.ACTION_DOWN)) { 1152 1153 if (event.getRepeatCount() == 0) { 1154 // Mute ONLY on the initial keypress. 1155 if (VDBG) Log.d(LOG_TAG, "MediaButtonBroadcastReceiver: HEADSETHOOK down!"); 1156 boolean consumed = PhoneUtils.handleHeadsetHook(phone); 1157 if (VDBG) Log.d(LOG_TAG, "==> handleHeadsetHook(): consumed = " + consumed); 1158 if (consumed) { 1159 abortBroadcast(); 1160 } 1161 } else if (phone.getState() != Phone.State.IDLE) { 1162 // As for any DOWN events other than the initial press, we consume 1163 // (and ignore) those too if the phone is in use. (Otherwise the 1164 // music player will handle them, which would be confusing.) 1165 abortBroadcast(); 1166 } 1167 } 1168 } 1169 } 1170 handleServiceStateChanged(Intent intent)1171 private void handleServiceStateChanged(Intent intent) { 1172 /** 1173 * This used to handle updating EriTextWidgetProvider this routine 1174 * and and listening for ACTION_SERVICE_STATE_CHANGED intents could 1175 * be removed. But leaving just in case it might be needed in the near 1176 * future. 1177 */ 1178 1179 // If service just returned, start sending out the queued messages 1180 ServiceState ss = ServiceState.newFromBundle(intent.getExtras()); 1181 1182 boolean hasService = true; 1183 boolean isCdma = false; 1184 String eriText = ""; 1185 1186 if (ss != null) { 1187 int state = ss.getState(); 1188 switch (state) { 1189 case ServiceState.STATE_OUT_OF_SERVICE: 1190 case ServiceState.STATE_POWER_OFF: 1191 hasService = false; 1192 break; 1193 } 1194 } else { 1195 hasService = false; 1196 } 1197 } 1198 } 1199