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