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 17package com.android.phone; 18 19import android.app.Activity; 20import android.app.KeyguardManager; 21import android.app.PendingIntent; 22import android.app.ProgressDialog; 23import android.app.TaskStackBuilder; 24import android.bluetooth.BluetoothAdapter; 25import android.bluetooth.IBluetoothHeadsetPhone; 26import android.content.ActivityNotFoundException; 27import android.content.BroadcastReceiver; 28import android.content.ComponentName; 29import android.content.ContentResolver; 30import android.content.Context; 31import android.content.ContextWrapper; 32import android.content.Intent; 33import android.content.IntentFilter; 34import android.content.ServiceConnection; 35import android.content.res.Configuration; 36import android.media.AudioManager; 37import android.net.Uri; 38import android.os.AsyncResult; 39import android.os.Binder; 40import android.os.Handler; 41import android.os.IBinder; 42import android.os.IPowerManager; 43import android.os.Message; 44import android.os.PowerManager; 45import android.os.RemoteException; 46import android.os.ServiceManager; 47import android.os.SystemClock; 48import android.os.SystemProperties; 49import android.os.UpdateLock; 50import android.os.UserHandle; 51import android.preference.PreferenceManager; 52import android.provider.Settings.System; 53import android.telephony.ServiceState; 54import android.text.TextUtils; 55import android.util.Log; 56import android.util.Slog; 57import android.view.KeyEvent; 58 59import com.android.internal.telephony.Call; 60import com.android.internal.telephony.CallManager; 61import com.android.internal.telephony.IccCard; 62import com.android.internal.telephony.IccCardConstants; 63import com.android.internal.telephony.MmiCode; 64import com.android.internal.telephony.Phone; 65import com.android.internal.telephony.PhoneConstants; 66import com.android.internal.telephony.PhoneFactory; 67import com.android.internal.telephony.TelephonyCapabilities; 68import com.android.internal.telephony.TelephonyIntents; 69import com.android.internal.telephony.cdma.TtyIntent; 70import com.android.phone.common.CallLogAsync; 71import com.android.phone.OtaUtils.CdmaOtaScreenState; 72import com.android.phone.WiredHeadsetManager.WiredHeadsetListener; 73import com.android.server.sip.SipService; 74import com.android.services.telephony.common.AudioMode; 75 76/** 77 * Global state for the telephony subsystem when running in the primary 78 * phone process. 79 */ 80public class PhoneGlobals extends ContextWrapper implements WiredHeadsetListener { 81 /* package */ static final String LOG_TAG = "PhoneApp"; 82 83 /** 84 * Phone app-wide debug level: 85 * 0 - no debug logging 86 * 1 - normal debug logging if ro.debuggable is set (which is true in 87 * "eng" and "userdebug" builds but not "user" builds) 88 * 2 - ultra-verbose debug logging 89 * 90 * Most individual classes in the phone app have a local DBG constant, 91 * typically set to 92 * (PhoneApp.DBG_LEVEL >= 1) && (SystemProperties.getInt("ro.debuggable", 0) == 1) 93 * or else 94 * (PhoneApp.DBG_LEVEL >= 2) 95 * depending on the desired verbosity. 96 * 97 * ***** DO NOT SUBMIT WITH DBG_LEVEL > 0 ************* 98 */ 99 /* package */ static final int DBG_LEVEL = 0; 100 101 private static final boolean DBG = 102 (PhoneGlobals.DBG_LEVEL >= 1) && (SystemProperties.getInt("ro.debuggable", 0) == 1); 103 private static final boolean VDBG = (PhoneGlobals.DBG_LEVEL >= 2); 104 105 // Message codes; see mHandler below. 106 private static final int EVENT_SIM_NETWORK_LOCKED = 3; 107 private static final int EVENT_SIM_STATE_CHANGED = 8; 108 private static final int EVENT_DATA_ROAMING_DISCONNECTED = 10; 109 private static final int EVENT_DATA_ROAMING_OK = 11; 110 private static final int EVENT_UNSOL_CDMA_INFO_RECORD = 12; 111 private static final int EVENT_DOCK_STATE_CHANGED = 13; 112 private static final int EVENT_TTY_PREFERRED_MODE_CHANGED = 14; 113 private static final int EVENT_TTY_MODE_GET = 15; 114 private static final int EVENT_TTY_MODE_SET = 16; 115 private static final int EVENT_START_SIP_SERVICE = 17; 116 117 // The MMI codes are also used by the InCallScreen. 118 public static final int MMI_INITIATE = 51; 119 public static final int MMI_COMPLETE = 52; 120 public static final int MMI_CANCEL = 53; 121 // Don't use message codes larger than 99 here; those are reserved for 122 // the individual Activities of the Phone UI. 123 124 /** 125 * Allowable values for the wake lock code. 126 * SLEEP means the device can be put to sleep. 127 * PARTIAL means wake the processor, but we display can be kept off. 128 * FULL means wake both the processor and the display. 129 */ 130 public enum WakeState { 131 SLEEP, 132 PARTIAL, 133 FULL 134 } 135 136 /** 137 * Intent Action used for hanging up the current call from Notification bar. This will 138 * choose first ringing call, first active call, or first background call (typically in 139 * HOLDING state). 140 */ 141 public static final String ACTION_HANG_UP_ONGOING_CALL = 142 "com.android.phone.ACTION_HANG_UP_ONGOING_CALL"; 143 144 /** 145 * Intent Action used for making a phone call from Notification bar. 146 * This is for missed call notifications. 147 */ 148 public static final String ACTION_CALL_BACK_FROM_NOTIFICATION = 149 "com.android.phone.ACTION_CALL_BACK_FROM_NOTIFICATION"; 150 151 /** 152 * Intent Action used for sending a SMS from notification bar. 153 * This is for missed call notifications. 154 */ 155 public static final String ACTION_SEND_SMS_FROM_NOTIFICATION = 156 "com.android.phone.ACTION_SEND_SMS_FROM_NOTIFICATION"; 157 158 private static PhoneGlobals sMe; 159 160 // A few important fields we expose to the rest of the package 161 // directly (rather than thru set/get methods) for efficiency. 162 CallController callController; 163 CallManager mCM; 164 CallNotifier notifier; 165 CallerInfoCache callerInfoCache; 166 NotificationMgr notificationMgr; 167 Phone phone; 168 PhoneInterfaceManager phoneMgr; 169 170 private AudioRouter audioRouter; 171 private BluetoothManager bluetoothManager; 172 private CallCommandService callCommandService; 173 private CallGatewayManager callGatewayManager; 174 private CallHandlerServiceProxy callHandlerServiceProxy; 175 private CallModeler callModeler; 176 private CallStateMonitor callStateMonitor; 177 private DTMFTonePlayer dtmfTonePlayer; 178 private IBluetoothHeadsetPhone mBluetoothPhone; 179 private Ringer ringer; 180 private WiredHeadsetManager wiredHeadsetManager; 181 182 static int mDockState = Intent.EXTRA_DOCK_STATE_UNDOCKED; 183 static boolean sVoiceCapable = true; 184 185 // Internal PhoneApp Call state tracker 186 CdmaPhoneCallState cdmaPhoneCallState; 187 188 // The currently-active PUK entry activity and progress dialog. 189 // Normally, these are the Emergency Dialer and the subsequent 190 // progress dialog. null if there is are no such objects in 191 // the foreground. 192 private Activity mPUKEntryActivity; 193 private ProgressDialog mPUKEntryProgressDialog; 194 195 private boolean mIsSimPinEnabled; 196 private String mCachedSimPin; 197 198 // True if we are beginning a call, but the phone state has not changed yet 199 private boolean mBeginningCall; 200 201 // Last phone state seen by updatePhoneState() 202 private PhoneConstants.State mLastPhoneState = PhoneConstants.State.IDLE; 203 204 private WakeState mWakeState = WakeState.SLEEP; 205 206 private PowerManager mPowerManager; 207 private IPowerManager mPowerManagerService; 208 private PowerManager.WakeLock mWakeLock; 209 private PowerManager.WakeLock mPartialWakeLock; 210 private KeyguardManager mKeyguardManager; 211 212 private UpdateLock mUpdateLock; 213 214 // Broadcast receiver for various intent broadcasts (see onCreate()) 215 private final BroadcastReceiver mReceiver = new PhoneAppBroadcastReceiver(); 216 217 // Broadcast receiver purely for ACTION_MEDIA_BUTTON broadcasts 218 private final BroadcastReceiver mMediaButtonReceiver = new MediaButtonBroadcastReceiver(); 219 220 /** boolean indicating restoring mute state on InCallScreen.onResume() */ 221 private boolean mShouldRestoreMuteOnInCallResume; 222 223 /** 224 * The singleton OtaUtils instance used for OTASP calls. 225 * 226 * The OtaUtils instance is created lazily the first time we need to 227 * make an OTASP call, regardless of whether it's an interactive or 228 * non-interactive OTASP call. 229 */ 230 public OtaUtils otaUtils; 231 232 // Following are the CDMA OTA information Objects used during OTA Call. 233 // cdmaOtaProvisionData object store static OTA information that needs 234 // to be maintained even during Slider open/close scenarios. 235 // cdmaOtaConfigData object stores configuration info to control visiblity 236 // of each OTA Screens. 237 // cdmaOtaScreenState object store OTA Screen State information. 238 public OtaUtils.CdmaOtaProvisionData cdmaOtaProvisionData; 239 public OtaUtils.CdmaOtaConfigData cdmaOtaConfigData; 240 public OtaUtils.CdmaOtaScreenState cdmaOtaScreenState; 241 public OtaUtils.CdmaOtaInCallScreenUiState cdmaOtaInCallScreenUiState; 242 243 // TTY feature enabled on this platform 244 private boolean mTtyEnabled; 245 // Current TTY operating mode selected by user 246 private int mPreferredTtyMode = Phone.TTY_MODE_OFF; 247 248 /** 249 * Set the restore mute state flag. Used when we are setting the mute state 250 * OUTSIDE of user interaction {@link PhoneUtils#startNewCall(Phone)} 251 */ 252 /*package*/void setRestoreMuteOnInCallResume (boolean mode) { 253 mShouldRestoreMuteOnInCallResume = mode; 254 } 255 256 Handler mHandler = new Handler() { 257 @Override 258 public void handleMessage(Message msg) { 259 PhoneConstants.State phoneState; 260 switch (msg.what) { 261 // Starts the SIP service. It's a no-op if SIP API is not supported 262 // on the deivce. 263 // TODO: Having the phone process host the SIP service is only 264 // temporary. Will move it to a persistent communication process 265 // later. 266 case EVENT_START_SIP_SERVICE: 267 SipService.start(getApplicationContext()); 268 break; 269 270 // TODO: This event should be handled by the lock screen, just 271 // like the "SIM missing" and "Sim locked" cases (bug 1804111). 272 case EVENT_SIM_NETWORK_LOCKED: 273 if (getResources().getBoolean(R.bool.ignore_sim_network_locked_events)) { 274 // Some products don't have the concept of a "SIM network lock" 275 Log.i(LOG_TAG, "Ignoring EVENT_SIM_NETWORK_LOCKED event; " 276 + "not showing 'SIM network unlock' PIN entry screen"); 277 } else { 278 // Normal case: show the "SIM network unlock" PIN entry screen. 279 // The user won't be able to do anything else until 280 // they enter a valid SIM network PIN. 281 Log.i(LOG_TAG, "show sim depersonal panel"); 282 IccNetworkDepersonalizationPanel ndpPanel = 283 new IccNetworkDepersonalizationPanel(PhoneGlobals.getInstance()); 284 ndpPanel.show(); 285 } 286 break; 287 288 case EVENT_DATA_ROAMING_DISCONNECTED: 289 notificationMgr.showDataDisconnectedRoaming(); 290 break; 291 292 case EVENT_DATA_ROAMING_OK: 293 notificationMgr.hideDataDisconnectedRoaming(); 294 break; 295 296 case MMI_COMPLETE: 297 onMMIComplete((AsyncResult) msg.obj); 298 break; 299 300 case MMI_CANCEL: 301 PhoneUtils.cancelMmiCode(phone); 302 break; 303 304 case EVENT_SIM_STATE_CHANGED: 305 // Marks the event where the SIM goes into ready state. 306 // Right now, this is only used for the PUK-unlocking 307 // process. 308 if (msg.obj.equals(IccCardConstants.INTENT_VALUE_ICC_READY)) { 309 // when the right event is triggered and there 310 // are UI objects in the foreground, we close 311 // them to display the lock panel. 312 if (mPUKEntryActivity != null) { 313 mPUKEntryActivity.finish(); 314 mPUKEntryActivity = null; 315 } 316 if (mPUKEntryProgressDialog != null) { 317 mPUKEntryProgressDialog.dismiss(); 318 mPUKEntryProgressDialog = null; 319 } 320 } 321 break; 322 323 case EVENT_UNSOL_CDMA_INFO_RECORD: 324 //TODO: handle message here; 325 break; 326 327 case EVENT_DOCK_STATE_CHANGED: 328 // If the phone is docked/undocked during a call, and no wired or BT headset 329 // is connected: turn on/off the speaker accordingly. 330 boolean inDockMode = false; 331 if (mDockState != Intent.EXTRA_DOCK_STATE_UNDOCKED) { 332 inDockMode = true; 333 } 334 if (VDBG) Log.d(LOG_TAG, "received EVENT_DOCK_STATE_CHANGED. Phone inDock = " 335 + inDockMode); 336 337 phoneState = mCM.getState(); 338 if (phoneState == PhoneConstants.State.OFFHOOK && 339 !wiredHeadsetManager.isHeadsetPlugged() && 340 !bluetoothManager.isBluetoothHeadsetAudioOn()) { 341 audioRouter.setSpeaker(inDockMode); 342 343 PhoneUtils.turnOnSpeaker(getApplicationContext(), inDockMode, true); 344 } 345 break; 346 347 case EVENT_TTY_PREFERRED_MODE_CHANGED: 348 // TTY mode is only applied if a headset is connected 349 int ttyMode; 350 if (wiredHeadsetManager.isHeadsetPlugged()) { 351 ttyMode = mPreferredTtyMode; 352 } else { 353 ttyMode = Phone.TTY_MODE_OFF; 354 } 355 phone.setTTYMode(ttyMode, mHandler.obtainMessage(EVENT_TTY_MODE_SET)); 356 break; 357 358 case EVENT_TTY_MODE_GET: 359 handleQueryTTYModeResponse(msg); 360 break; 361 362 case EVENT_TTY_MODE_SET: 363 handleSetTTYModeResponse(msg); 364 break; 365 } 366 } 367 }; 368 369 public PhoneGlobals(Context context) { 370 super(context); 371 sMe = this; 372 } 373 374 public void onCreate() { 375 if (VDBG) Log.v(LOG_TAG, "onCreate()..."); 376 377 ContentResolver resolver = getContentResolver(); 378 379 // Cache the "voice capable" flag. 380 // This flag currently comes from a resource (which is 381 // overrideable on a per-product basis): 382 sVoiceCapable = 383 getResources().getBoolean(com.android.internal.R.bool.config_voice_capable); 384 // ...but this might eventually become a PackageManager "system 385 // feature" instead, in which case we'd do something like: 386 // sVoiceCapable = 387 // getPackageManager().hasSystemFeature(PackageManager.FEATURE_TELEPHONY_VOICE_CALLS); 388 389 if (phone == null) { 390 // Initialize the telephony framework 391 PhoneFactory.makeDefaultPhones(this); 392 393 // Get the default phone 394 phone = PhoneFactory.getDefaultPhone(); 395 396 // Start TelephonyDebugService After the default phone is created. 397 Intent intent = new Intent(this, TelephonyDebugService.class); 398 startService(intent); 399 400 mCM = CallManager.getInstance(); 401 mCM.registerPhone(phone); 402 403 // Create the NotificationMgr singleton, which is used to display 404 // status bar icons and control other status bar behavior. 405 notificationMgr = NotificationMgr.init(this); 406 407 mHandler.sendEmptyMessage(EVENT_START_SIP_SERVICE); 408 409 int phoneType = phone.getPhoneType(); 410 411 if (phoneType == PhoneConstants.PHONE_TYPE_CDMA) { 412 // Create an instance of CdmaPhoneCallState and initialize it to IDLE 413 cdmaPhoneCallState = new CdmaPhoneCallState(); 414 cdmaPhoneCallState.CdmaPhoneCallStateInit(); 415 } 416 417 if (BluetoothAdapter.getDefaultAdapter() != null) { 418 // Start BluetoothPhoneService even if device is not voice capable. 419 // The device can still support VOIP. 420 startService(new Intent(this, BluetoothPhoneService.class)); 421 bindService(new Intent(this, BluetoothPhoneService.class), 422 mBluetoothPhoneConnection, 0); 423 } else { 424 // Device is not bluetooth capable 425 mBluetoothPhone = null; 426 } 427 428 // before registering for phone state changes 429 mPowerManager = (PowerManager) getSystemService(Context.POWER_SERVICE); 430 mWakeLock = mPowerManager.newWakeLock(PowerManager.FULL_WAKE_LOCK, LOG_TAG); 431 // lock used to keep the processor awake, when we don't care for the display. 432 mPartialWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK 433 | PowerManager.ON_AFTER_RELEASE, LOG_TAG); 434 435 mKeyguardManager = (KeyguardManager) getSystemService(Context.KEYGUARD_SERVICE); 436 437 // get a handle to the service so that we can use it later when we 438 // want to set the poke lock. 439 mPowerManagerService = IPowerManager.Stub.asInterface( 440 ServiceManager.getService("power")); 441 442 // Get UpdateLock to suppress system-update related events (e.g. dialog show-up) 443 // during phone calls. 444 mUpdateLock = new UpdateLock("phone"); 445 446 if (DBG) Log.d(LOG_TAG, "onCreate: mUpdateLock: " + mUpdateLock); 447 448 CallLogger callLogger = new CallLogger(this, new CallLogAsync()); 449 450 callGatewayManager = new CallGatewayManager(); 451 452 // Create the CallController singleton, which is the interface 453 // to the telephony layer for user-initiated telephony functionality 454 // (like making outgoing calls.) 455 callController = CallController.init(this, callLogger, callGatewayManager); 456 457 // Create the CallerInfoCache singleton, which remembers custom ring tone and 458 // send-to-voicemail settings. 459 // 460 // The asynchronous caching will start just after this call. 461 callerInfoCache = CallerInfoCache.init(this); 462 463 // Monitors call activity from the telephony layer 464 callStateMonitor = new CallStateMonitor(mCM); 465 466 // Creates call models for use with CallHandlerService. 467 callModeler = new CallModeler(callStateMonitor, mCM, callGatewayManager); 468 469 // Plays DTMF Tones 470 dtmfTonePlayer = new DTMFTonePlayer(mCM, callModeler); 471 472 // Manages wired headset state 473 wiredHeadsetManager = new WiredHeadsetManager(this); 474 wiredHeadsetManager.addWiredHeadsetListener(this); 475 476 // Bluetooth manager 477 bluetoothManager = new BluetoothManager(this, mCM, callModeler); 478 479 ringer = Ringer.init(this, bluetoothManager); 480 481 // Audio router 482 audioRouter = new AudioRouter(this, bluetoothManager, wiredHeadsetManager, mCM); 483 484 // Service used by in-call UI to control calls 485 callCommandService = new CallCommandService(this, mCM, callModeler, dtmfTonePlayer, 486 audioRouter); 487 488 // Sends call state to the UI 489 callHandlerServiceProxy = new CallHandlerServiceProxy(this, callModeler, 490 callCommandService, audioRouter); 491 492 phoneMgr = PhoneInterfaceManager.init(this, phone, callHandlerServiceProxy); 493 494 // Create the CallNotifer singleton, which handles 495 // asynchronous events from the telephony layer (like 496 // launching the incoming-call UI when an incoming call comes 497 // in.) 498 notifier = CallNotifier.init(this, phone, ringer, callLogger, callStateMonitor, 499 bluetoothManager, callModeler); 500 501 // register for ICC status 502 IccCard sim = phone.getIccCard(); 503 if (sim != null) { 504 if (VDBG) Log.v(LOG_TAG, "register for ICC status"); 505 sim.registerForNetworkLocked(mHandler, EVENT_SIM_NETWORK_LOCKED, null); 506 } 507 508 // register for MMI/USSD 509 mCM.registerForMmiComplete(mHandler, MMI_COMPLETE, null); 510 511 // register connection tracking to PhoneUtils 512 PhoneUtils.initializeConnectionHandler(mCM); 513 514 // Read platform settings for TTY feature 515 mTtyEnabled = getResources().getBoolean(R.bool.tty_enabled); 516 517 // Register for misc other intent broadcasts. 518 IntentFilter intentFilter = 519 new IntentFilter(Intent.ACTION_AIRPLANE_MODE_CHANGED); 520 intentFilter.addAction(TelephonyIntents.ACTION_ANY_DATA_CONNECTION_STATE_CHANGED); 521 intentFilter.addAction(Intent.ACTION_DOCK_EVENT); 522 intentFilter.addAction(TelephonyIntents.ACTION_SIM_STATE_CHANGED); 523 intentFilter.addAction(TelephonyIntents.ACTION_RADIO_TECHNOLOGY_CHANGED); 524 intentFilter.addAction(TelephonyIntents.ACTION_SERVICE_STATE_CHANGED); 525 intentFilter.addAction(TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED); 526 if (mTtyEnabled) { 527 intentFilter.addAction(TtyIntent.TTY_PREFERRED_MODE_CHANGE_ACTION); 528 } 529 intentFilter.addAction(AudioManager.RINGER_MODE_CHANGED_ACTION); 530 registerReceiver(mReceiver, intentFilter); 531 532 // Use a separate receiver for ACTION_MEDIA_BUTTON broadcasts, 533 // since we need to manually adjust its priority (to make sure 534 // we get these intents *before* the media player.) 535 IntentFilter mediaButtonIntentFilter = 536 new IntentFilter(Intent.ACTION_MEDIA_BUTTON); 537 // TODO verify the independent priority doesn't need to be handled thanks to the 538 // private intent handler registration 539 // Make sure we're higher priority than the media player's 540 // MediaButtonIntentReceiver (which currently has the default 541 // priority of zero; see apps/Music/AndroidManifest.xml.) 542 mediaButtonIntentFilter.setPriority(1); 543 // 544 registerReceiver(mMediaButtonReceiver, mediaButtonIntentFilter); 545 // register the component so it gets priority for calls 546 AudioManager am = (AudioManager) getSystemService(Context.AUDIO_SERVICE); 547 am.registerMediaButtonEventReceiverForCalls(new ComponentName(this.getPackageName(), 548 MediaButtonBroadcastReceiver.class.getName())); 549 550 //set the default values for the preferences in the phone. 551 PreferenceManager.setDefaultValues(this, R.xml.network_setting, false); 552 553 PreferenceManager.setDefaultValues(this, R.xml.call_feature_setting, false); 554 555 // Make sure the audio mode (along with some 556 // audio-mode-related state of our own) is initialized 557 // correctly, given the current state of the phone. 558 PhoneUtils.setAudioMode(mCM); 559 } 560 561 if (TelephonyCapabilities.supportsOtasp(phone)) { 562 cdmaOtaProvisionData = new OtaUtils.CdmaOtaProvisionData(); 563 cdmaOtaConfigData = new OtaUtils.CdmaOtaConfigData(); 564 cdmaOtaScreenState = new OtaUtils.CdmaOtaScreenState(); 565 cdmaOtaInCallScreenUiState = new OtaUtils.CdmaOtaInCallScreenUiState(); 566 } 567 568 // XXX pre-load the SimProvider so that it's ready 569 resolver.getType(Uri.parse("content://icc/adn")); 570 571 // start with the default value to set the mute state. 572 mShouldRestoreMuteOnInCallResume = false; 573 574 // TODO: Register for Cdma Information Records 575 // phone.registerCdmaInformationRecord(mHandler, EVENT_UNSOL_CDMA_INFO_RECORD, null); 576 577 // Read TTY settings and store it into BP NV. 578 // AP owns (i.e. stores) the TTY setting in AP settings database and pushes the setting 579 // to BP at power up (BP does not need to make the TTY setting persistent storage). 580 // This way, there is a single owner (i.e AP) for the TTY setting in the phone. 581 if (mTtyEnabled) { 582 mPreferredTtyMode = android.provider.Settings.Secure.getInt( 583 phone.getContext().getContentResolver(), 584 android.provider.Settings.Secure.PREFERRED_TTY_MODE, 585 Phone.TTY_MODE_OFF); 586 mHandler.sendMessage(mHandler.obtainMessage(EVENT_TTY_PREFERRED_MODE_CHANGED, 0)); 587 } 588 // Read HAC settings and configure audio hardware 589 if (getResources().getBoolean(R.bool.hac_enabled)) { 590 int hac = android.provider.Settings.System.getInt(phone.getContext().getContentResolver(), 591 android.provider.Settings.System.HEARING_AID, 592 0); 593 AudioManager audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE); 594 audioManager.setParameter(CallFeaturesSetting.HAC_KEY, hac != 0 ? 595 CallFeaturesSetting.HAC_VAL_ON : 596 CallFeaturesSetting.HAC_VAL_OFF); 597 } 598 } 599 600 /** 601 * Returns the singleton instance of the PhoneApp. 602 */ 603 static PhoneGlobals getInstance() { 604 if (sMe == null) { 605 throw new IllegalStateException("No PhoneGlobals here!"); 606 } 607 return sMe; 608 } 609 610 /** 611 * Returns the singleton instance of the PhoneApp if running as the 612 * primary user, otherwise null. 613 */ 614 static PhoneGlobals getInstanceIfPrimary() { 615 return sMe; 616 } 617 618 /** 619 * Returns the Phone associated with this instance 620 */ 621 static Phone getPhone() { 622 return getInstance().phone; 623 } 624 625 Ringer getRinger() { 626 return ringer; 627 } 628 629 IBluetoothHeadsetPhone getBluetoothPhoneService() { 630 return mBluetoothPhone; 631 } 632 633 /* package */ BluetoothManager getBluetoothManager() { 634 return bluetoothManager; 635 } 636 637 /* package */ WiredHeadsetManager getWiredHeadsetManager() { 638 return wiredHeadsetManager; 639 } 640 641 /* package */ AudioRouter getAudioRouter() { 642 return audioRouter; 643 } 644 645 /* package */ CallModeler getCallModeler() { 646 return callModeler; 647 } 648 649 /* package */ CallManager getCallManager() { 650 return mCM; 651 } 652 653 /** 654 * Returns an Intent that can be used to go to the "Call log" 655 * UI (aka CallLogActivity) in the Contacts app. 656 * 657 * Watch out: there's no guarantee that the system has any activity to 658 * handle this intent. (In particular there may be no "Call log" at 659 * all on on non-voice-capable devices.) 660 */ 661 /* package */ static Intent createCallLogIntent() { 662 Intent intent = new Intent(Intent.ACTION_VIEW, null); 663 intent.setType("vnd.android.cursor.dir/calls"); 664 return intent; 665 } 666 667 /* package */static PendingIntent createPendingCallLogIntent(Context context) { 668 final Intent callLogIntent = PhoneGlobals.createCallLogIntent(); 669 final TaskStackBuilder taskStackBuilder = TaskStackBuilder.create(context); 670 taskStackBuilder.addNextIntent(callLogIntent); 671 return taskStackBuilder.getPendingIntent(0, 0); 672 } 673 674 /** 675 * Returns PendingIntent for hanging up ongoing phone call. This will typically be used from 676 * Notification context. 677 */ 678 /* package */ static PendingIntent createHangUpOngoingCallPendingIntent(Context context) { 679 Intent intent = new Intent(PhoneGlobals.ACTION_HANG_UP_ONGOING_CALL, null, 680 context, NotificationBroadcastReceiver.class); 681 return PendingIntent.getBroadcast(context, 0, intent, 0); 682 } 683 684 /* package */ static PendingIntent getCallBackPendingIntent(Context context, String number) { 685 Intent intent = new Intent(ACTION_CALL_BACK_FROM_NOTIFICATION, 686 Uri.fromParts(Constants.SCHEME_TEL, number, null), 687 context, NotificationBroadcastReceiver.class); 688 return PendingIntent.getBroadcast(context, 0, intent, 0); 689 } 690 691 /* package */ static PendingIntent getSendSmsFromNotificationPendingIntent( 692 Context context, String number) { 693 Intent intent = new Intent(ACTION_SEND_SMS_FROM_NOTIFICATION, 694 Uri.fromParts(Constants.SCHEME_SMSTO, number, null), 695 context, NotificationBroadcastReceiver.class); 696 return PendingIntent.getBroadcast(context, 0, intent, 0); 697 } 698 699 boolean isSimPinEnabled() { 700 return mIsSimPinEnabled; 701 } 702 703 boolean authenticateAgainstCachedSimPin(String pin) { 704 return (mCachedSimPin != null && mCachedSimPin.equals(pin)); 705 } 706 707 void setCachedSimPin(String pin) { 708 mCachedSimPin = pin; 709 } 710 711 /** 712 * Handles OTASP-related events from the telephony layer. 713 * 714 * While an OTASP call is active, the CallNotifier forwards 715 * OTASP-related telephony events to this method. 716 */ 717 void handleOtaspEvent(Message msg) { 718 if (DBG) Log.d(LOG_TAG, "handleOtaspEvent(message " + msg + ")..."); 719 720 if (otaUtils == null) { 721 // We shouldn't be getting OTASP events without ever 722 // having started the OTASP call in the first place! 723 Log.w(LOG_TAG, "handleOtaEvents: got an event but otaUtils is null! " 724 + "message = " + msg); 725 return; 726 } 727 728 otaUtils.onOtaProvisionStatusChanged((AsyncResult) msg.obj); 729 } 730 731 /** 732 * Similarly, handle the disconnect event of an OTASP call 733 * by forwarding it to the OtaUtils instance. 734 */ 735 /* package */ void handleOtaspDisconnect() { 736 if (DBG) Log.d(LOG_TAG, "handleOtaspDisconnect()..."); 737 738 if (otaUtils == null) { 739 // We shouldn't be getting OTASP events without ever 740 // having started the OTASP call in the first place! 741 Log.w(LOG_TAG, "handleOtaspDisconnect: otaUtils is null!"); 742 return; 743 } 744 745 otaUtils.onOtaspDisconnect(); 746 } 747 748 /** 749 * Sets the activity responsible for un-PUK-blocking the device 750 * so that we may close it when we receive a positive result. 751 * mPUKEntryActivity is also used to indicate to the device that 752 * we are trying to un-PUK-lock the phone. In other words, iff 753 * it is NOT null, then we are trying to unlock and waiting for 754 * the SIM to move to READY state. 755 * 756 * @param activity is the activity to close when PUK has 757 * finished unlocking. Can be set to null to indicate the unlock 758 * or SIM READYing process is over. 759 */ 760 void setPukEntryActivity(Activity activity) { 761 mPUKEntryActivity = activity; 762 } 763 764 Activity getPUKEntryActivity() { 765 return mPUKEntryActivity; 766 } 767 768 /** 769 * Sets the dialog responsible for notifying the user of un-PUK- 770 * blocking - SIM READYing progress, so that we may dismiss it 771 * when we receive a positive result. 772 * 773 * @param dialog indicates the progress dialog informing the user 774 * of the state of the device. Dismissed upon completion of 775 * READYing process 776 */ 777 void setPukEntryProgressDialog(ProgressDialog dialog) { 778 mPUKEntryProgressDialog = dialog; 779 } 780 781 ProgressDialog getPUKEntryProgressDialog() { 782 return mPUKEntryProgressDialog; 783 } 784 785 /** 786 * Controls whether or not the screen is allowed to sleep. 787 * 788 * Once sleep is allowed (WakeState is SLEEP), it will rely on the 789 * settings for the poke lock to determine when to timeout and let 790 * the device sleep {@link PhoneGlobals#setScreenTimeout}. 791 * 792 * @param ws tells the device to how to wake. 793 */ 794 /* package */ void requestWakeState(WakeState ws) { 795 if (VDBG) Log.d(LOG_TAG, "requestWakeState(" + ws + ")..."); 796 synchronized (this) { 797 if (mWakeState != ws) { 798 switch (ws) { 799 case PARTIAL: 800 // acquire the processor wake lock, and release the FULL 801 // lock if it is being held. 802 mPartialWakeLock.acquire(); 803 if (mWakeLock.isHeld()) { 804 mWakeLock.release(); 805 } 806 break; 807 case FULL: 808 // acquire the full wake lock, and release the PARTIAL 809 // lock if it is being held. 810 mWakeLock.acquire(); 811 if (mPartialWakeLock.isHeld()) { 812 mPartialWakeLock.release(); 813 } 814 break; 815 case SLEEP: 816 default: 817 // release both the PARTIAL and FULL locks. 818 if (mWakeLock.isHeld()) { 819 mWakeLock.release(); 820 } 821 if (mPartialWakeLock.isHeld()) { 822 mPartialWakeLock.release(); 823 } 824 break; 825 } 826 mWakeState = ws; 827 } 828 } 829 } 830 831 /** 832 * If we are not currently keeping the screen on, then poke the power 833 * manager to wake up the screen for the user activity timeout duration. 834 */ 835 /* package */ void wakeUpScreen() { 836 synchronized (this) { 837 if (mWakeState == WakeState.SLEEP) { 838 if (DBG) Log.d(LOG_TAG, "pulse screen lock"); 839 mPowerManager.wakeUp(SystemClock.uptimeMillis()); 840 } 841 } 842 } 843 844 /** 845 * Sets the wake state and screen timeout based on the current state 846 * of the phone, and the current state of the in-call UI. 847 * 848 * This method is a "UI Policy" wrapper around 849 * {@link PhoneGlobals#requestWakeState} and {@link PhoneGlobals#setScreenTimeout}. 850 * 851 * It's safe to call this method regardless of the state of the Phone 852 * (e.g. whether or not it's idle), and regardless of the state of the 853 * Phone UI (e.g. whether or not the InCallScreen is active.) 854 */ 855 /* package */ void updateWakeState() { 856 PhoneConstants.State state = mCM.getState(); 857 858 // True if the speakerphone is in use. (If so, we *always* use 859 // the default timeout. Since the user is obviously not holding 860 // the phone up to his/her face, we don't need to worry about 861 // false touches, and thus don't need to turn the screen off so 862 // aggressively.) 863 // Note that we need to make a fresh call to this method any 864 // time the speaker state changes. (That happens in 865 // PhoneUtils.turnOnSpeaker().) 866 boolean isSpeakerInUse = (state == PhoneConstants.State.OFFHOOK) && PhoneUtils.isSpeakerOn(this); 867 868 // TODO (bug 1440854): The screen timeout *might* also need to 869 // depend on the bluetooth state, but this isn't as clear-cut as 870 // the speaker state (since while using BT it's common for the 871 // user to put the phone straight into a pocket, in which case the 872 // timeout should probably still be short.) 873 874 // Decide whether to force the screen on or not. 875 // 876 // Force the screen to be on if the phone is ringing or dialing, 877 // or if we're displaying the "Call ended" UI for a connection in 878 // the "disconnected" state. 879 // However, if the phone is disconnected while the user is in the 880 // middle of selecting a quick response message, we should not force 881 // the screen to be on. 882 // 883 boolean isRinging = (state == PhoneConstants.State.RINGING); 884 boolean isDialing = (phone.getForegroundCall().getState() == Call.State.DIALING); 885 boolean keepScreenOn = isRinging || isDialing; 886 // keepScreenOn == true means we'll hold a full wake lock: 887 requestWakeState(keepScreenOn ? WakeState.FULL : WakeState.SLEEP); 888 } 889 890 /** 891 * Manually pokes the PowerManager's userActivity method. Since we 892 * set the {@link WindowManager.LayoutParams#INPUT_FEATURE_DISABLE_USER_ACTIVITY} 893 * flag while the InCallScreen is active when there is no proximity sensor, 894 * we need to do this for touch events that really do count as user activity 895 * (like pressing any onscreen UI elements.) 896 */ 897 /* package */ void pokeUserActivity() { 898 if (VDBG) Log.d(LOG_TAG, "pokeUserActivity()..."); 899 mPowerManager.userActivity(SystemClock.uptimeMillis(), false); 900 } 901 902 /** 903 * Notifies the phone app when the phone state changes. 904 * 905 * This method will updates various states inside Phone app (e.g. update-lock state, etc.) 906 */ 907 /* package */ void updatePhoneState(PhoneConstants.State state) { 908 if (state != mLastPhoneState) { 909 mLastPhoneState = state; 910 911 // Try to acquire or release UpdateLock. 912 // 913 // Watch out: we don't release the lock here when the screen is still in foreground. 914 // At that time InCallScreen will release it on onPause(). 915 if (state != PhoneConstants.State.IDLE) { 916 // UpdateLock is a recursive lock, while we may get "acquire" request twice and 917 // "release" request once for a single call (RINGING + OFFHOOK and IDLE). 918 // We need to manually ensure the lock is just acquired once for each (and this 919 // will prevent other possible buggy situations too). 920 if (!mUpdateLock.isHeld()) { 921 mUpdateLock.acquire(); 922 } 923 } else { 924 if (mUpdateLock.isHeld()) { 925 mUpdateLock.release(); 926 } 927 } 928 } 929 } 930 931 /* package */ PhoneConstants.State getPhoneState() { 932 return mLastPhoneState; 933 } 934 935 KeyguardManager getKeyguardManager() { 936 return mKeyguardManager; 937 } 938 939 private void onMMIComplete(AsyncResult r) { 940 if (VDBG) Log.d(LOG_TAG, "onMMIComplete()..."); 941 MmiCode mmiCode = (MmiCode) r.result; 942 PhoneUtils.displayMMIComplete(phone, getInstance(), mmiCode, null, null); 943 } 944 945 private void initForNewRadioTechnology() { 946 if (DBG) Log.d(LOG_TAG, "initForNewRadioTechnology..."); 947 948 if (phone.getPhoneType() == PhoneConstants.PHONE_TYPE_CDMA) { 949 // Create an instance of CdmaPhoneCallState and initialize it to IDLE 950 cdmaPhoneCallState = new CdmaPhoneCallState(); 951 cdmaPhoneCallState.CdmaPhoneCallStateInit(); 952 } 953 if (TelephonyCapabilities.supportsOtasp(phone)) { 954 //create instances of CDMA OTA data classes 955 if (cdmaOtaProvisionData == null) { 956 cdmaOtaProvisionData = new OtaUtils.CdmaOtaProvisionData(); 957 } 958 if (cdmaOtaConfigData == null) { 959 cdmaOtaConfigData = new OtaUtils.CdmaOtaConfigData(); 960 } 961 if (cdmaOtaScreenState == null) { 962 cdmaOtaScreenState = new OtaUtils.CdmaOtaScreenState(); 963 } 964 if (cdmaOtaInCallScreenUiState == null) { 965 cdmaOtaInCallScreenUiState = new OtaUtils.CdmaOtaInCallScreenUiState(); 966 } 967 } else { 968 //Clean up OTA data in GSM/UMTS. It is valid only for CDMA 969 clearOtaState(); 970 } 971 972 ringer.updateRingerContextAfterRadioTechnologyChange(this.phone); 973 notifier.updateCallNotifierRegistrationsAfterRadioTechnologyChange(); 974 callStateMonitor.updateAfterRadioTechnologyChange(); 975 976 if (mBluetoothPhone != null) { 977 try { 978 mBluetoothPhone.updateBtHandsfreeAfterRadioTechnologyChange(); 979 } catch (RemoteException e) { 980 Log.e(LOG_TAG, Log.getStackTraceString(new Throwable())); 981 } 982 } 983 984 // Update registration for ICC status after radio technology change 985 IccCard sim = phone.getIccCard(); 986 if (sim != null) { 987 if (DBG) Log.d(LOG_TAG, "Update registration for ICC status..."); 988 989 //Register all events new to the new active phone 990 sim.registerForNetworkLocked(mHandler, EVENT_SIM_NETWORK_LOCKED, null); 991 } 992 } 993 994 995 /** 996 * This is called when the wired headset state changes. 997 */ 998 @Override 999 public void onWiredHeadsetConnection(boolean pluggedIn) { 1000 PhoneConstants.State phoneState = mCM.getState(); 1001 1002 // Force TTY state update according to new headset state 1003 if (mTtyEnabled) { 1004 mHandler.sendMessage(mHandler.obtainMessage(EVENT_TTY_PREFERRED_MODE_CHANGED, 0)); 1005 } 1006 } 1007 1008 /** 1009 * Receiver for misc intent broadcasts the Phone app cares about. 1010 */ 1011 private class PhoneAppBroadcastReceiver extends BroadcastReceiver { 1012 @Override 1013 public void onReceive(Context context, Intent intent) { 1014 String action = intent.getAction(); 1015 if (action.equals(Intent.ACTION_AIRPLANE_MODE_CHANGED)) { 1016 boolean enabled = System.getInt(getContentResolver(), 1017 System.AIRPLANE_MODE_ON, 0) == 0; 1018 phone.setRadioPower(enabled); 1019 } else if (action.equals(TelephonyIntents.ACTION_ANY_DATA_CONNECTION_STATE_CHANGED)) { 1020 if (VDBG) Log.d(LOG_TAG, "mReceiver: ACTION_ANY_DATA_CONNECTION_STATE_CHANGED"); 1021 if (VDBG) Log.d(LOG_TAG, "- state: " + intent.getStringExtra(PhoneConstants.STATE_KEY)); 1022 if (VDBG) Log.d(LOG_TAG, "- reason: " 1023 + intent.getStringExtra(PhoneConstants.STATE_CHANGE_REASON_KEY)); 1024 1025 // The "data disconnected due to roaming" notification is shown 1026 // if (a) you have the "data roaming" feature turned off, and 1027 // (b) you just lost data connectivity because you're roaming. 1028 boolean disconnectedDueToRoaming = 1029 !phone.getDataRoamingEnabled() 1030 && "DISCONNECTED".equals(intent.getStringExtra(PhoneConstants.STATE_KEY)) 1031 && Phone.REASON_ROAMING_ON.equals( 1032 intent.getStringExtra(PhoneConstants.STATE_CHANGE_REASON_KEY)); 1033 mHandler.sendEmptyMessage(disconnectedDueToRoaming 1034 ? EVENT_DATA_ROAMING_DISCONNECTED 1035 : EVENT_DATA_ROAMING_OK); 1036 } else if ((action.equals(TelephonyIntents.ACTION_SIM_STATE_CHANGED)) && 1037 (mPUKEntryActivity != null)) { 1038 // if an attempt to un-PUK-lock the device was made, while we're 1039 // receiving this state change notification, notify the handler. 1040 // NOTE: This is ONLY triggered if an attempt to un-PUK-lock has 1041 // been attempted. 1042 mHandler.sendMessage(mHandler.obtainMessage(EVENT_SIM_STATE_CHANGED, 1043 intent.getStringExtra(IccCardConstants.INTENT_KEY_ICC_STATE))); 1044 } else if (action.equals(TelephonyIntents.ACTION_RADIO_TECHNOLOGY_CHANGED)) { 1045 String newPhone = intent.getStringExtra(PhoneConstants.PHONE_NAME_KEY); 1046 Log.d(LOG_TAG, "Radio technology switched. Now " + newPhone + " is active."); 1047 initForNewRadioTechnology(); 1048 } else if (action.equals(TelephonyIntents.ACTION_SERVICE_STATE_CHANGED)) { 1049 handleServiceStateChanged(intent); 1050 } else if (action.equals(TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED)) { 1051 if (TelephonyCapabilities.supportsEcm(phone)) { 1052 Log.d(LOG_TAG, "Emergency Callback Mode arrived in PhoneApp."); 1053 // Start Emergency Callback Mode service 1054 if (intent.getBooleanExtra("phoneinECMState", false)) { 1055 context.startService(new Intent(context, 1056 EmergencyCallbackModeService.class)); 1057 } 1058 } else { 1059 // It doesn't make sense to get ACTION_EMERGENCY_CALLBACK_MODE_CHANGED 1060 // on a device that doesn't support ECM in the first place. 1061 Log.e(LOG_TAG, "Got ACTION_EMERGENCY_CALLBACK_MODE_CHANGED, " 1062 + "but ECM isn't supported for phone: " + phone.getPhoneName()); 1063 } 1064 } else if (action.equals(Intent.ACTION_DOCK_EVENT)) { 1065 mDockState = intent.getIntExtra(Intent.EXTRA_DOCK_STATE, 1066 Intent.EXTRA_DOCK_STATE_UNDOCKED); 1067 if (VDBG) Log.d(LOG_TAG, "ACTION_DOCK_EVENT -> mDockState = " + mDockState); 1068 mHandler.sendMessage(mHandler.obtainMessage(EVENT_DOCK_STATE_CHANGED, 0)); 1069 } else if (action.equals(TtyIntent.TTY_PREFERRED_MODE_CHANGE_ACTION)) { 1070 mPreferredTtyMode = intent.getIntExtra(TtyIntent.TTY_PREFFERED_MODE, 1071 Phone.TTY_MODE_OFF); 1072 if (VDBG) Log.d(LOG_TAG, "mReceiver: TTY_PREFERRED_MODE_CHANGE_ACTION"); 1073 if (VDBG) Log.d(LOG_TAG, " mode: " + mPreferredTtyMode); 1074 mHandler.sendMessage(mHandler.obtainMessage(EVENT_TTY_PREFERRED_MODE_CHANGED, 0)); 1075 } else if (action.equals(AudioManager.RINGER_MODE_CHANGED_ACTION)) { 1076 int ringerMode = intent.getIntExtra(AudioManager.EXTRA_RINGER_MODE, 1077 AudioManager.RINGER_MODE_NORMAL); 1078 if (ringerMode == AudioManager.RINGER_MODE_SILENT) { 1079 notifier.silenceRinger(); 1080 } 1081 } 1082 } 1083 } 1084 1085 /** 1086 * Broadcast receiver for the ACTION_MEDIA_BUTTON broadcast intent. 1087 * 1088 * This functionality isn't lumped in with the other intents in 1089 * PhoneAppBroadcastReceiver because we instantiate this as a totally 1090 * separate BroadcastReceiver instance, since we need to manually 1091 * adjust its IntentFilter's priority (to make sure we get these 1092 * intents *before* the media player.) 1093 */ 1094 private class MediaButtonBroadcastReceiver extends BroadcastReceiver { 1095 @Override 1096 public void onReceive(Context context, Intent intent) { 1097 KeyEvent event = (KeyEvent) intent.getParcelableExtra(Intent.EXTRA_KEY_EVENT); 1098 if (VDBG) Log.d(LOG_TAG, 1099 "MediaButtonBroadcastReceiver.onReceive()... event = " + event); 1100 if ((event != null) 1101 && (event.getKeyCode() == KeyEvent.KEYCODE_HEADSETHOOK)) { 1102 if (VDBG) Log.d(LOG_TAG, "MediaButtonBroadcastReceiver: HEADSETHOOK"); 1103 boolean consumed = PhoneUtils.handleHeadsetHook(phone, event); 1104 if (VDBG) Log.d(LOG_TAG, "==> handleHeadsetHook(): consumed = " + consumed); 1105 if (consumed) { 1106 abortBroadcast(); 1107 } 1108 } else { 1109 if (mCM.getState() != PhoneConstants.State.IDLE) { 1110 // If the phone is anything other than completely idle, 1111 // then we consume and ignore any media key events, 1112 // Otherwise it is too easy to accidentally start 1113 // playing music while a phone call is in progress. 1114 if (VDBG) Log.d(LOG_TAG, "MediaButtonBroadcastReceiver: consumed"); 1115 abortBroadcast(); 1116 } 1117 } 1118 } 1119 } 1120 1121 /** 1122 * Accepts broadcast Intents which will be prepared by {@link NotificationMgr} and thus 1123 * sent from framework's notification mechanism (which is outside Phone context). 1124 * This should be visible from outside, but shouldn't be in "exported" state. 1125 * 1126 * TODO: If possible merge this into PhoneAppBroadcastReceiver. 1127 */ 1128 public static class NotificationBroadcastReceiver extends BroadcastReceiver { 1129 @Override 1130 public void onReceive(Context context, Intent intent) { 1131 String action = intent.getAction(); 1132 // TODO: use "if (VDBG)" here. 1133 Log.d(LOG_TAG, "Broadcast from Notification: " + action); 1134 1135 if (action.equals(ACTION_HANG_UP_ONGOING_CALL)) { 1136 PhoneUtils.hangup(PhoneGlobals.getInstance().mCM); 1137 } else if (action.equals(ACTION_CALL_BACK_FROM_NOTIFICATION)) { 1138 // Collapse the expanded notification and the notification item itself. 1139 closeSystemDialogs(context); 1140 clearMissedCallNotification(context); 1141 1142 Intent callIntent = new Intent(Intent.ACTION_CALL_PRIVILEGED, intent.getData()); 1143 callIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK 1144 | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS); 1145 context.startActivity(callIntent); 1146 } else if (action.equals(ACTION_SEND_SMS_FROM_NOTIFICATION)) { 1147 // Collapse the expanded notification and the notification item itself. 1148 closeSystemDialogs(context); 1149 clearMissedCallNotification(context); 1150 1151 Intent smsIntent = new Intent(Intent.ACTION_SENDTO, intent.getData()); 1152 smsIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 1153 context.startActivity(smsIntent); 1154 } else { 1155 Log.w(LOG_TAG, "Received hang-up request from notification," 1156 + " but there's no call the system can hang up."); 1157 } 1158 } 1159 1160 private void closeSystemDialogs(Context context) { 1161 Intent intent = new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS); 1162 context.sendBroadcastAsUser(intent, UserHandle.ALL); 1163 } 1164 1165 private void clearMissedCallNotification(Context context) { 1166 Intent clearIntent = new Intent(context, ClearMissedCallsService.class); 1167 clearIntent.setAction(ClearMissedCallsService.ACTION_CLEAR_MISSED_CALLS); 1168 context.startService(clearIntent); 1169 } 1170 } 1171 1172 private void handleServiceStateChanged(Intent intent) { 1173 /** 1174 * This used to handle updating EriTextWidgetProvider this routine 1175 * and and listening for ACTION_SERVICE_STATE_CHANGED intents could 1176 * be removed. But leaving just in case it might be needed in the near 1177 * future. 1178 */ 1179 1180 // If service just returned, start sending out the queued messages 1181 ServiceState ss = ServiceState.newFromBundle(intent.getExtras()); 1182 1183 if (ss != null) { 1184 int state = ss.getState(); 1185 notificationMgr.updateNetworkSelection(state); 1186 } 1187 } 1188 1189 public boolean isOtaCallInActiveState() { 1190 boolean otaCallActive = false; 1191 if (VDBG) Log.d(LOG_TAG, "- isOtaCallInActiveState " + otaCallActive); 1192 return otaCallActive; 1193 } 1194 1195 public boolean isOtaCallInEndState() { 1196 boolean otaCallEnded = false; 1197 if (VDBG) Log.d(LOG_TAG, "- isOtaCallInEndState " + otaCallEnded); 1198 return otaCallEnded; 1199 } 1200 1201 // it is safe to call clearOtaState() even if the InCallScreen isn't active 1202 public void clearOtaState() { 1203 if (DBG) Log.d(LOG_TAG, "- clearOtaState ..."); 1204 if (otaUtils != null) { 1205 otaUtils.cleanOtaScreen(true); 1206 if (DBG) Log.d(LOG_TAG, " - clearOtaState clears OTA screen"); 1207 } 1208 } 1209 1210 // it is safe to call dismissOtaDialogs() even if the InCallScreen isn't active 1211 public void dismissOtaDialogs() { 1212 if (DBG) Log.d(LOG_TAG, "- dismissOtaDialogs ..."); 1213 if (otaUtils != null) { 1214 otaUtils.dismissAllOtaDialogs(); 1215 if (DBG) Log.d(LOG_TAG, " - dismissOtaDialogs clears OTA dialogs"); 1216 } 1217 } 1218 1219 private void handleQueryTTYModeResponse(Message msg) { 1220 AsyncResult ar = (AsyncResult) msg.obj; 1221 if (ar.exception != null) { 1222 if (DBG) Log.d(LOG_TAG, "handleQueryTTYModeResponse: Error getting TTY state."); 1223 } else { 1224 if (DBG) Log.d(LOG_TAG, 1225 "handleQueryTTYModeResponse: TTY enable state successfully queried."); 1226 1227 int ttymode = ((int[]) ar.result)[0]; 1228 if (DBG) Log.d(LOG_TAG, "handleQueryTTYModeResponse:ttymode=" + ttymode); 1229 1230 Intent ttyModeChanged = new Intent(TtyIntent.TTY_ENABLED_CHANGE_ACTION); 1231 ttyModeChanged.putExtra("ttyEnabled", ttymode != Phone.TTY_MODE_OFF); 1232 sendBroadcastAsUser(ttyModeChanged, UserHandle.ALL); 1233 1234 String audioTtyMode; 1235 switch (ttymode) { 1236 case Phone.TTY_MODE_FULL: 1237 audioTtyMode = "tty_full"; 1238 break; 1239 case Phone.TTY_MODE_VCO: 1240 audioTtyMode = "tty_vco"; 1241 break; 1242 case Phone.TTY_MODE_HCO: 1243 audioTtyMode = "tty_hco"; 1244 break; 1245 case Phone.TTY_MODE_OFF: 1246 default: 1247 audioTtyMode = "tty_off"; 1248 break; 1249 } 1250 AudioManager audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE); 1251 audioManager.setParameters("tty_mode="+audioTtyMode); 1252 } 1253 } 1254 1255 private void handleSetTTYModeResponse(Message msg) { 1256 AsyncResult ar = (AsyncResult) msg.obj; 1257 1258 if (ar.exception != null) { 1259 if (DBG) Log.d (LOG_TAG, 1260 "handleSetTTYModeResponse: Error setting TTY mode, ar.exception" 1261 + ar.exception); 1262 } 1263 phone.queryTTYMode(mHandler.obtainMessage(EVENT_TTY_MODE_GET)); 1264 } 1265 1266 /** 1267 * "Call origin" may be used by Contacts app to specify where the phone call comes from. 1268 * Currently, the only permitted value for this extra is {@link #ALLOWED_EXTRA_CALL_ORIGIN}. 1269 * Any other value will be ignored, to make sure that malicious apps can't trick the in-call 1270 * UI into launching some random other app after a call ends. 1271 * 1272 * TODO: make this more generic. Note that we should let the "origin" specify its package 1273 * while we are now assuming it is "com.android.contacts" 1274 */ 1275 public static final String EXTRA_CALL_ORIGIN = "com.android.phone.CALL_ORIGIN"; 1276 private static final String DEFAULT_CALL_ORIGIN_PACKAGE = "com.android.dialer"; 1277 private static final String ALLOWED_EXTRA_CALL_ORIGIN = 1278 "com.android.dialer.DialtactsActivity"; 1279 /** 1280 * Used to determine if the preserved call origin is fresh enough. 1281 */ 1282 private static final long CALL_ORIGIN_EXPIRATION_MILLIS = 30 * 1000; 1283 1284 /** Service connection */ 1285 private final ServiceConnection mBluetoothPhoneConnection = new ServiceConnection() { 1286 1287 /** Handle the task of binding the local object to the service */ 1288 public void onServiceConnected(ComponentName className, IBinder service) { 1289 Log.i(LOG_TAG, "Headset phone created, binding local service."); 1290 mBluetoothPhone = IBluetoothHeadsetPhone.Stub.asInterface(service); 1291 } 1292 1293 /** Handle the task of cleaning up the local binding */ 1294 public void onServiceDisconnected(ComponentName className) { 1295 Log.i(LOG_TAG, "Headset phone disconnected, cleaning local binding."); 1296 mBluetoothPhone = null; 1297 } 1298 }; 1299 1300} 1301