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