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