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