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