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     boolean isShowingCallScreenForProximity() {
    744         if (mInCallScreen == null) return false;
    745         return mInCallScreen.isForegroundActivityForProximity();
    746     }
    747 
    748     /**
    749      * Dismisses the in-call UI.
    750      *
    751      * This also ensures that you won't be able to get back to the in-call
    752      * UI via the BACK button (since this call removes the InCallScreen
    753      * from the activity history.)
    754      * For OTA Call, it call InCallScreen api to handle OTA Call End scenario
    755      * to display OTA Call End screen.
    756      */
    757     /* package */ void dismissCallScreen() {
    758         if (mInCallScreen != null) {
    759             if ((TelephonyCapabilities.supportsOtasp(phone)) &&
    760                     (mInCallScreen.isOtaCallInActiveState()
    761                     || mInCallScreen.isOtaCallInEndState()
    762                     || ((cdmaOtaScreenState != null)
    763                     && (cdmaOtaScreenState.otaScreenState
    764                             != CdmaOtaScreenState.OtaScreenState.OTA_STATUS_UNDEFINED)))) {
    765                 // TODO: During OTA Call, display should not become dark to
    766                 // allow user to see OTA UI update. Phone app needs to hold
    767                 // a SCREEN_DIM_WAKE_LOCK wake lock during the entire OTA call.
    768                 wakeUpScreen();
    769                 // If InCallScreen is not in foreground we resume it to show the OTA call end screen
    770                 // Fire off the InCallScreen intent
    771                 displayCallScreen();
    772 
    773                 mInCallScreen.handleOtaCallEnd();
    774                 return;
    775             } else {
    776                 mInCallScreen.finish();
    777             }
    778         }
    779     }
    780 
    781     /**
    782      * Handles OTASP-related events from the telephony layer.
    783      *
    784      * While an OTASP call is active, the CallNotifier forwards
    785      * OTASP-related telephony events to this method.
    786      */
    787     void handleOtaspEvent(Message msg) {
    788         if (DBG) Log.d(LOG_TAG, "handleOtaspEvent(message " + msg + ")...");
    789 
    790         if (otaUtils == null) {
    791             // We shouldn't be getting OTASP events without ever
    792             // having started the OTASP call in the first place!
    793             Log.w(LOG_TAG, "handleOtaEvents: got an event but otaUtils is null! "
    794                   + "message = " + msg);
    795             return;
    796         }
    797 
    798         otaUtils.onOtaProvisionStatusChanged((AsyncResult) msg.obj);
    799     }
    800 
    801     /**
    802      * Similarly, handle the disconnect event of an OTASP call
    803      * by forwarding it to the OtaUtils instance.
    804      */
    805     /* package */ void handleOtaspDisconnect() {
    806         if (DBG) Log.d(LOG_TAG, "handleOtaspDisconnect()...");
    807 
    808         if (otaUtils == null) {
    809             // We shouldn't be getting OTASP events without ever
    810             // having started the OTASP call in the first place!
    811             Log.w(LOG_TAG, "handleOtaspDisconnect: otaUtils is null!");
    812             return;
    813         }
    814 
    815         otaUtils.onOtaspDisconnect();
    816     }
    817 
    818     /**
    819      * Sets the activity responsible for un-PUK-blocking the device
    820      * so that we may close it when we receive a positive result.
    821      * mPUKEntryActivity is also used to indicate to the device that
    822      * we are trying to un-PUK-lock the phone. In other words, iff
    823      * it is NOT null, then we are trying to unlock and waiting for
    824      * the SIM to move to READY state.
    825      *
    826      * @param activity is the activity to close when PUK has
    827      * finished unlocking. Can be set to null to indicate the unlock
    828      * or SIM READYing process is over.
    829      */
    830     void setPukEntryActivity(Activity activity) {
    831         mPUKEntryActivity = activity;
    832     }
    833 
    834     Activity getPUKEntryActivity() {
    835         return mPUKEntryActivity;
    836     }
    837 
    838     /**
    839      * Sets the dialog responsible for notifying the user of un-PUK-
    840      * blocking - SIM READYing progress, so that we may dismiss it
    841      * when we receive a positive result.
    842      *
    843      * @param dialog indicates the progress dialog informing the user
    844      * of the state of the device.  Dismissed upon completion of
    845      * READYing process
    846      */
    847     void setPukEntryProgressDialog(ProgressDialog dialog) {
    848         mPUKEntryProgressDialog = dialog;
    849     }
    850 
    851     ProgressDialog getPUKEntryProgressDialog() {
    852         return mPUKEntryProgressDialog;
    853     }
    854 
    855     /**
    856      * Controls how quickly the screen times out.
    857      *
    858      * The poke lock controls how long it takes before the screen powers
    859      * down, and therefore has no immediate effect when the current
    860      * WakeState (see {@link PhoneApp#requestWakeState}) is FULL.
    861      * If we're in a state where the screen *is* allowed to turn off,
    862      * though, the poke lock will determine the timeout interval (long or
    863      * short).
    864      *
    865      * @param shortPokeLock tells the device the timeout duration to use
    866      * before going to sleep
    867      * {@link com.android.server.PowerManagerService#SHORT_KEYLIGHT_DELAY}.
    868      */
    869     /* package */ void setScreenTimeout(ScreenTimeoutDuration duration) {
    870         if (VDBG) Log.d(LOG_TAG, "setScreenTimeout(" + duration + ")...");
    871 
    872         // make sure we don't set the poke lock repeatedly so that we
    873         // avoid triggering the userActivity calls in
    874         // PowerManagerService.setPokeLock().
    875         if (duration == mScreenTimeoutDuration) {
    876             return;
    877         }
    878         // stick with default timeout if we are using the proximity sensor
    879         if (proximitySensorModeEnabled()) {
    880             return;
    881         }
    882         mScreenTimeoutDuration = duration;
    883         updatePokeLock();
    884     }
    885 
    886     /**
    887      * Update the state of the poke lock held by the phone app,
    888      * based on the current desired screen timeout and the
    889      * current "ignore user activity on touch" flag.
    890      */
    891     private void updatePokeLock() {
    892         // This is kind of convoluted, but the basic thing to remember is
    893         // that the poke lock just sends a message to the screen to tell
    894         // it to stay on for a while.
    895         // The default is 0, for a long timeout and should be set that way
    896         // when we are heading back into a the keyguard / screen off
    897         // state, and also when we're trying to keep the screen alive
    898         // while ringing.  We'll also want to ignore the cheek events
    899         // regardless of the timeout duration.
    900         // The short timeout is really used whenever we want to give up
    901         // the screen lock, such as when we're in call.
    902         int pokeLockSetting = 0;
    903         switch (mScreenTimeoutDuration) {
    904             case SHORT:
    905                 // Set the poke lock to timeout the display after a short
    906                 // timeout (5s). This ensures that the screen goes to sleep
    907                 // as soon as acceptably possible after we the wake lock
    908                 // has been released.
    909                 pokeLockSetting |= LocalPowerManager.POKE_LOCK_SHORT_TIMEOUT;
    910                 break;
    911 
    912             case MEDIUM:
    913                 // Set the poke lock to timeout the display after a medium
    914                 // timeout (15s). This ensures that the screen goes to sleep
    915                 // as soon as acceptably possible after we the wake lock
    916                 // has been released.
    917                 pokeLockSetting |= LocalPowerManager.POKE_LOCK_MEDIUM_TIMEOUT;
    918                 break;
    919 
    920             case DEFAULT:
    921             default:
    922                 // set the poke lock to timeout the display after a long
    923                 // delay by default.
    924                 // TODO: it may be nice to be able to disable cheek presses
    925                 // for long poke locks (emergency dialer, for instance).
    926                 break;
    927         }
    928 
    929         if (mIgnoreTouchUserActivity) {
    930             pokeLockSetting |= LocalPowerManager.POKE_LOCK_IGNORE_TOUCH_EVENTS;
    931         }
    932 
    933         // Send the request
    934         try {
    935             mPowerManagerService.setPokeLock(pokeLockSetting, mPokeLockToken, LOG_TAG);
    936         } catch (RemoteException e) {
    937             Log.w(LOG_TAG, "mPowerManagerService.setPokeLock() failed: " + e);
    938         }
    939     }
    940 
    941     /**
    942      * Controls whether or not the screen is allowed to sleep.
    943      *
    944      * Once sleep is allowed (WakeState is SLEEP), it will rely on the
    945      * settings for the poke lock to determine when to timeout and let
    946      * the device sleep {@link PhoneApp#setScreenTimeout}.
    947      *
    948      * @param ws tells the device to how to wake.
    949      */
    950     /* package */ void requestWakeState(WakeState ws) {
    951         if (VDBG) Log.d(LOG_TAG, "requestWakeState(" + ws + ")...");
    952         synchronized (this) {
    953             if (mWakeState != ws) {
    954                 switch (ws) {
    955                     case PARTIAL:
    956                         // acquire the processor wake lock, and release the FULL
    957                         // lock if it is being held.
    958                         mPartialWakeLock.acquire();
    959                         if (mWakeLock.isHeld()) {
    960                             mWakeLock.release();
    961                         }
    962                         break;
    963                     case FULL:
    964                         // acquire the full wake lock, and release the PARTIAL
    965                         // lock if it is being held.
    966                         mWakeLock.acquire();
    967                         if (mPartialWakeLock.isHeld()) {
    968                             mPartialWakeLock.release();
    969                         }
    970                         break;
    971                     case SLEEP:
    972                     default:
    973                         // release both the PARTIAL and FULL locks.
    974                         if (mWakeLock.isHeld()) {
    975                             mWakeLock.release();
    976                         }
    977                         if (mPartialWakeLock.isHeld()) {
    978                             mPartialWakeLock.release();
    979                         }
    980                         break;
    981                 }
    982                 mWakeState = ws;
    983             }
    984         }
    985     }
    986 
    987     /**
    988      * If we are not currently keeping the screen on, then poke the power
    989      * manager to wake up the screen for the user activity timeout duration.
    990      */
    991     /* package */ void wakeUpScreen() {
    992         synchronized (this) {
    993             if (mWakeState == WakeState.SLEEP) {
    994                 if (DBG) Log.d(LOG_TAG, "pulse screen lock");
    995                 try {
    996                     mPowerManagerService.userActivityWithForce(SystemClock.uptimeMillis(), false, true);
    997                 } catch (RemoteException ex) {
    998                     // Ignore -- the system process is dead.
    999                 }
   1000             }
   1001         }
   1002     }
   1003 
   1004     /**
   1005      * Sets the wake state and screen timeout based on the current state
   1006      * of the phone, and the current state of the in-call UI.
   1007      *
   1008      * This method is a "UI Policy" wrapper around
   1009      * {@link PhoneApp#requestWakeState} and {@link PhoneApp#setScreenTimeout}.
   1010      *
   1011      * It's safe to call this method regardless of the state of the Phone
   1012      * (e.g. whether or not it's idle), and regardless of the state of the
   1013      * Phone UI (e.g. whether or not the InCallScreen is active.)
   1014      */
   1015     /* package */ void updateWakeState() {
   1016         Phone.State state = mCM.getState();
   1017 
   1018         // True if the in-call UI is the foreground activity.
   1019         // (Note this will be false if the screen is currently off,
   1020         // since in that case *no* activity is in the foreground.)
   1021         boolean isShowingCallScreen = isShowingCallScreen();
   1022 
   1023         // True if the InCallScreen's DTMF dialer is currently opened.
   1024         // (Note this does NOT imply whether or not the InCallScreen
   1025         // itself is visible.)
   1026         boolean isDialerOpened = (mInCallScreen != null) && mInCallScreen.isDialerOpened();
   1027 
   1028         // True if the speakerphone is in use.  (If so, we *always* use
   1029         // the default timeout.  Since the user is obviously not holding
   1030         // the phone up to his/her face, we don't need to worry about
   1031         // false touches, and thus don't need to turn the screen off so
   1032         // aggressively.)
   1033         // Note that we need to make a fresh call to this method any
   1034         // time the speaker state changes.  (That happens in
   1035         // PhoneUtils.turnOnSpeaker().)
   1036         boolean isSpeakerInUse = (state == Phone.State.OFFHOOK) && PhoneUtils.isSpeakerOn(this);
   1037 
   1038         // TODO (bug 1440854): The screen timeout *might* also need to
   1039         // depend on the bluetooth state, but this isn't as clear-cut as
   1040         // the speaker state (since while using BT it's common for the
   1041         // user to put the phone straight into a pocket, in which case the
   1042         // timeout should probably still be short.)
   1043 
   1044         if (DBG) Log.d(LOG_TAG, "updateWakeState: callscreen " + isShowingCallScreen
   1045                        + ", dialer " + isDialerOpened
   1046                        + ", speaker " + isSpeakerInUse + "...");
   1047 
   1048         //
   1049         // (1) Set the screen timeout.
   1050         //
   1051         // Note that the "screen timeout" value we determine here is
   1052         // meaningless if the screen is forced on (see (2) below.)
   1053         //
   1054 
   1055         // Historical note: In froyo and earlier, we checked here for a special
   1056         // case: the in-call UI being active, the speaker off, and the DTMF dialpad
   1057         // not visible.  In that case, with no touchable UI onscreen at all (for
   1058         // non-prox-sensor devices at least), we could assume the user was probably
   1059         // holding the phone up to their face and *not* actually looking at the
   1060         // screen.  So we'd switch to a special screen timeout value
   1061         // (ScreenTimeoutDuration.MEDIUM), purely to save battery life.
   1062         //
   1063         // On current devices, we can rely on the proximity sensor to turn the
   1064         // screen off in this case, so we use the system-wide default timeout
   1065         // unconditionally.
   1066         setScreenTimeout(ScreenTimeoutDuration.DEFAULT);
   1067 
   1068         //
   1069         // (2) Decide whether to force the screen on or not.
   1070         //
   1071         // Force the screen to be on if the phone is ringing or dialing,
   1072         // or if we're displaying the "Call ended" UI for a connection in
   1073         // the "disconnected" state.
   1074         //
   1075         boolean isRinging = (state == Phone.State.RINGING);
   1076         boolean isDialing = (phone.getForegroundCall().getState() == Call.State.DIALING);
   1077         boolean showingDisconnectedConnection =
   1078                 PhoneUtils.hasDisconnectedConnections(phone) && isShowingCallScreen;
   1079         boolean keepScreenOn = isRinging || isDialing || showingDisconnectedConnection;
   1080         if (DBG) Log.d(LOG_TAG, "updateWakeState: keepScreenOn = " + keepScreenOn
   1081                        + " (isRinging " + isRinging
   1082                        + ", isDialing " + isDialing
   1083                        + ", showingDisc " + showingDisconnectedConnection + ")");
   1084         // keepScreenOn == true means we'll hold a full wake lock:
   1085         requestWakeState(keepScreenOn ? WakeState.FULL : WakeState.SLEEP);
   1086     }
   1087 
   1088     /**
   1089      * Wrapper around the PowerManagerService.preventScreenOn() API.
   1090      * This allows the in-call UI to prevent the screen from turning on
   1091      * even if a subsequent call to updateWakeState() causes us to acquire
   1092      * a full wake lock.
   1093      */
   1094     /* package */ void preventScreenOn(boolean prevent) {
   1095         if (VDBG) Log.d(LOG_TAG, "- preventScreenOn(" + prevent + ")...");
   1096         try {
   1097             mPowerManagerService.preventScreenOn(prevent);
   1098         } catch (RemoteException e) {
   1099             Log.w(LOG_TAG, "mPowerManagerService.preventScreenOn() failed: " + e);
   1100         }
   1101     }
   1102 
   1103     /**
   1104      * Sets or clears the flag that tells the PowerManager that touch
   1105      * (and cheek) events should NOT be considered "user activity".
   1106      *
   1107      * Since the in-call UI is totally insensitive to touch in most
   1108      * states, we set this flag whenever the InCallScreen is in the
   1109      * foreground.  (Otherwise, repeated unintentional touches could
   1110      * prevent the device from going to sleep.)
   1111      *
   1112      * There *are* some some touch events that really do count as user
   1113      * activity, though.  For those, we need to manually poke the
   1114      * PowerManager's userActivity method; see pokeUserActivity().
   1115      */
   1116     /* package */ void setIgnoreTouchUserActivity(boolean ignore) {
   1117         if (VDBG) Log.d(LOG_TAG, "setIgnoreTouchUserActivity(" + ignore + ")...");
   1118         mIgnoreTouchUserActivity = ignore;
   1119         updatePokeLock();
   1120     }
   1121 
   1122     /**
   1123      * Manually pokes the PowerManager's userActivity method.  Since we
   1124      * hold the POKE_LOCK_IGNORE_TOUCH_EVENTS poke lock while
   1125      * the InCallScreen is active, we need to do this for touch events
   1126      * that really do count as user activity (like pressing any
   1127      * onscreen UI elements.)
   1128      */
   1129     /* package */ void pokeUserActivity() {
   1130         if (VDBG) Log.d(LOG_TAG, "pokeUserActivity()...");
   1131         try {
   1132             mPowerManagerService.userActivity(SystemClock.uptimeMillis(), false);
   1133         } catch (RemoteException e) {
   1134             Log.w(LOG_TAG, "mPowerManagerService.userActivity() failed: " + e);
   1135         }
   1136     }
   1137 
   1138     /**
   1139      * Set when a new outgoing call is beginning, so we can update
   1140      * the proximity sensor state.
   1141      * Cleared when the InCallScreen is no longer in the foreground,
   1142      * in case the call fails without changing the telephony state.
   1143      */
   1144     /* package */ void setBeginningCall(boolean beginning) {
   1145         // Note that we are beginning a new call, for proximity sensor support
   1146         mBeginningCall = beginning;
   1147         // Update the Proximity sensor based on mBeginningCall state
   1148         updateProximitySensorMode(mCM.getState());
   1149     }
   1150 
   1151     /**
   1152      * Updates the wake lock used to control proximity sensor behavior,
   1153      * based on the current state of the phone.  This method is called
   1154      * from the CallNotifier on any phone state change.
   1155      *
   1156      * On devices that have a proximity sensor, to avoid false touches
   1157      * during a call, we hold a PROXIMITY_SCREEN_OFF_WAKE_LOCK wake lock
   1158      * whenever the phone is off hook.  (When held, that wake lock causes
   1159      * the screen to turn off automatically when the sensor detects an
   1160      * object close to the screen.)
   1161      *
   1162      * This method is a no-op for devices that don't have a proximity
   1163      * sensor.
   1164      *
   1165      * Note this method doesn't care if the InCallScreen is the foreground
   1166      * activity or not.  That's because we want the proximity sensor to be
   1167      * enabled any time the phone is in use, to avoid false cheek events
   1168      * for whatever app you happen to be running.
   1169      *
   1170      * Proximity wake lock will *not* be held if any one of the
   1171      * conditions is true while on a call:
   1172      * 1) If the audio is routed via Bluetooth
   1173      * 2) If a wired headset is connected
   1174      * 3) if the speaker is ON
   1175      * 4) If the slider is open(i.e. the hardkeyboard is *not* hidden)
   1176      *
   1177      * @param state current state of the phone (see {@link Phone#State})
   1178      */
   1179     /* package */ void updateProximitySensorMode(Phone.State state) {
   1180         if (VDBG) Log.d(LOG_TAG, "updateProximitySensorMode: state = " + state);
   1181 
   1182         if (proximitySensorModeEnabled()) {
   1183             synchronized (mProximityWakeLock) {
   1184                 // turn proximity sensor off and turn screen on immediately if
   1185                 // we are using a headset, the keyboard is open, or the device
   1186                 // is being held in a horizontal position.
   1187                 boolean screenOnImmediately = (isHeadsetPlugged()
   1188                             || PhoneUtils.isSpeakerOn(this)
   1189                             || ((mBtHandsfree != null) && mBtHandsfree.isAudioOn())
   1190                             || mIsHardKeyboardOpen);
   1191 
   1192                 // We do not keep the screen off when the user is outside in-call screen and we are
   1193                 // horizontal, but we do not force it on when we become horizontal until the
   1194                 // proximity sensor goes negative.
   1195                 boolean horizontal =
   1196                         (mOrientation == AccelerometerListener.ORIENTATION_HORIZONTAL);
   1197                 screenOnImmediately |= !isShowingCallScreenForProximity() && horizontal;
   1198 
   1199                 if (((state == Phone.State.OFFHOOK) || mBeginningCall) && !screenOnImmediately) {
   1200                     // Phone is in use!  Arrange for the screen to turn off
   1201                     // automatically when the sensor detects a close object.
   1202                     if (!mProximityWakeLock.isHeld()) {
   1203                         if (DBG) Log.d(LOG_TAG, "updateProximitySensorMode: acquiring...");
   1204                         mProximityWakeLock.acquire();
   1205                     } else {
   1206                         if (VDBG) Log.d(LOG_TAG, "updateProximitySensorMode: lock already held.");
   1207                     }
   1208                 } else {
   1209                     // Phone is either idle, or ringing.  We don't want any
   1210                     // special proximity sensor behavior in either case.
   1211                     if (mProximityWakeLock.isHeld()) {
   1212                         if (DBG) Log.d(LOG_TAG, "updateProximitySensorMode: releasing...");
   1213                         // Wait until user has moved the phone away from his head if we are
   1214                         // releasing due to the phone call ending.
   1215                         // Qtherwise, turn screen on immediately
   1216                         int flags =
   1217                             (screenOnImmediately ? 0 : PowerManager.WAIT_FOR_PROXIMITY_NEGATIVE);
   1218                         mProximityWakeLock.release(flags);
   1219                     } else {
   1220                         if (VDBG) {
   1221                             Log.d(LOG_TAG, "updateProximitySensorMode: lock already released.");
   1222                         }
   1223                     }
   1224                 }
   1225             }
   1226         }
   1227     }
   1228 
   1229     public void orientationChanged(int orientation) {
   1230         mOrientation = orientation;
   1231         updateProximitySensorMode(mCM.getState());
   1232     }
   1233 
   1234     /**
   1235      * Notifies the phone app when the phone state changes.
   1236      * Currently used only for proximity sensor support.
   1237      */
   1238     /* package */ void updatePhoneState(Phone.State state) {
   1239         if (state != mLastPhoneState) {
   1240             mLastPhoneState = state;
   1241             updateProximitySensorMode(state);
   1242             if (mAccelerometerListener != null) {
   1243                 // use accelerometer to augment proximity sensor when in call
   1244                 mOrientation = AccelerometerListener.ORIENTATION_UNKNOWN;
   1245                 mAccelerometerListener.enable(state == Phone.State.OFFHOOK);
   1246             }
   1247             // clear our beginning call flag
   1248             mBeginningCall = false;
   1249             // While we are in call, the in-call screen should dismiss the keyguard.
   1250             // This allows the user to press Home to go directly home without going through
   1251             // an insecure lock screen.
   1252             // But we do not want to do this if there is no active call so we do not
   1253             // bypass the keyguard if the call is not answered or declined.
   1254             if (mInCallScreen != null) {
   1255                 mInCallScreen.updateKeyguardPolicy(state == Phone.State.OFFHOOK);
   1256             }
   1257         }
   1258     }
   1259 
   1260     /* package */ Phone.State getPhoneState() {
   1261         return mLastPhoneState;
   1262     }
   1263 
   1264     /**
   1265      * @return true if this device supports the "proximity sensor
   1266      * auto-lock" feature while in-call (see updateProximitySensorMode()).
   1267      */
   1268     /* package */ boolean proximitySensorModeEnabled() {
   1269         return (mProximityWakeLock != null);
   1270     }
   1271 
   1272     KeyguardManager getKeyguardManager() {
   1273         return mKeyguardManager;
   1274     }
   1275 
   1276     private void onMMIComplete(AsyncResult r) {
   1277         if (VDBG) Log.d(LOG_TAG, "onMMIComplete()...");
   1278         MmiCode mmiCode = (MmiCode) r.result;
   1279         PhoneUtils.displayMMIComplete(phone, getInstance(), mmiCode, null, null);
   1280     }
   1281 
   1282     private void initForNewRadioTechnology() {
   1283         if (DBG) Log.d(LOG_TAG, "initForNewRadioTechnology...");
   1284 
   1285          if (phone.getPhoneType() == Phone.PHONE_TYPE_CDMA) {
   1286             // Create an instance of CdmaPhoneCallState and initialize it to IDLE
   1287             cdmaPhoneCallState = new CdmaPhoneCallState();
   1288             cdmaPhoneCallState.CdmaPhoneCallStateInit();
   1289         }
   1290         if (TelephonyCapabilities.supportsOtasp(phone)) {
   1291             //create instances of CDMA OTA data classes
   1292             if (cdmaOtaProvisionData == null) {
   1293                 cdmaOtaProvisionData = new OtaUtils.CdmaOtaProvisionData();
   1294             }
   1295             if (cdmaOtaConfigData == null) {
   1296                 cdmaOtaConfigData = new OtaUtils.CdmaOtaConfigData();
   1297             }
   1298             if (cdmaOtaScreenState == null) {
   1299                 cdmaOtaScreenState = new OtaUtils.CdmaOtaScreenState();
   1300             }
   1301             if (cdmaOtaInCallScreenUiState == null) {
   1302                 cdmaOtaInCallScreenUiState = new OtaUtils.CdmaOtaInCallScreenUiState();
   1303             }
   1304         } else {
   1305             //Clean up OTA data in GSM/UMTS. It is valid only for CDMA
   1306             clearOtaState();
   1307         }
   1308 
   1309         ringer.updateRingerContextAfterRadioTechnologyChange(this.phone);
   1310         notifier.updateCallNotifierRegistrationsAfterRadioTechnologyChange();
   1311         if (mBtHandsfree != null) {
   1312             mBtHandsfree.updateBtHandsfreeAfterRadioTechnologyChange();
   1313         }
   1314         if (mInCallScreen != null) {
   1315             mInCallScreen.updateAfterRadioTechnologyChange();
   1316         }
   1317 
   1318         // Update registration for ICC status after radio technology change
   1319         IccCard sim = phone.getIccCard();
   1320         if (sim != null) {
   1321             if (DBG) Log.d(LOG_TAG, "Update registration for ICC status...");
   1322 
   1323             //Register all events new to the new active phone
   1324             sim.registerForNetworkLocked(mHandler, EVENT_SIM_NETWORK_LOCKED, null);
   1325         }
   1326     }
   1327 
   1328 
   1329     /**
   1330      * @return true if a wired headset is currently plugged in.
   1331      *
   1332      * @see Intent.ACTION_HEADSET_PLUG (which we listen for in mReceiver.onReceive())
   1333      */
   1334     boolean isHeadsetPlugged() {
   1335         return mIsHeadsetPlugged;
   1336     }
   1337 
   1338     /**
   1339      * @return true if the onscreen UI should currently be showing the
   1340      * special "bluetooth is active" indication in a couple of places (in
   1341      * which UI elements turn blue and/or show the bluetooth logo.)
   1342      *
   1343      * This depends on the BluetoothHeadset state *and* the current
   1344      * telephony state; see shouldShowBluetoothIndication().
   1345      *
   1346      * @see CallCard
   1347      * @see NotificationMgr.updateInCallNotification
   1348      */
   1349     /* package */ boolean showBluetoothIndication() {
   1350         return mShowBluetoothIndication;
   1351     }
   1352 
   1353     /**
   1354      * Recomputes the mShowBluetoothIndication flag based on the current
   1355      * bluetooth state and current telephony state.
   1356      *
   1357      * This needs to be called any time the bluetooth headset state or the
   1358      * telephony state changes.
   1359      *
   1360      * @param forceUiUpdate if true, force the UI elements that care
   1361      *                      about this flag to update themselves.
   1362      */
   1363     /* package */ void updateBluetoothIndication(boolean forceUiUpdate) {
   1364         mShowBluetoothIndication = shouldShowBluetoothIndication(mBluetoothHeadsetState,
   1365                                                                  mBluetoothHeadsetAudioState,
   1366                                                                  mCM);
   1367         if (forceUiUpdate) {
   1368             // Post Handler messages to the various components that might
   1369             // need to be refreshed based on the new state.
   1370             if (isShowingCallScreen()) mInCallScreen.requestUpdateBluetoothIndication();
   1371             if (DBG) Log.d (LOG_TAG, "- updating in-call notification for BT state change...");
   1372             mHandler.sendEmptyMessage(EVENT_UPDATE_INCALL_NOTIFICATION);
   1373         }
   1374 
   1375         // Update the Proximity sensor based on Bluetooth audio state
   1376         updateProximitySensorMode(mCM.getState());
   1377     }
   1378 
   1379     /**
   1380      * UI policy helper function for the couple of places in the UI that
   1381      * have some way of indicating that "bluetooth is in use."
   1382      *
   1383      * @return true if the onscreen UI should indicate that "bluetooth is in use",
   1384      *         based on the specified bluetooth headset state, and the
   1385      *         current state of the phone.
   1386      * @see showBluetoothIndication()
   1387      */
   1388     private static boolean shouldShowBluetoothIndication(int bluetoothState,
   1389                                                          int bluetoothAudioState,
   1390                                                          CallManager cm) {
   1391         // We want the UI to indicate that "bluetooth is in use" in two
   1392         // slightly different cases:
   1393         //
   1394         // (a) The obvious case: if a bluetooth headset is currently in
   1395         //     use for an ongoing call.
   1396         //
   1397         // (b) The not-so-obvious case: if an incoming call is ringing,
   1398         //     and we expect that audio *will* be routed to a bluetooth
   1399         //     headset once the call is answered.
   1400 
   1401         switch (cm.getState()) {
   1402             case OFFHOOK:
   1403                 // This covers normal active calls, and also the case if
   1404                 // the foreground call is DIALING or ALERTING.  In this
   1405                 // case, bluetooth is considered "active" if a headset
   1406                 // is connected *and* audio is being routed to it.
   1407                 return ((bluetoothState == BluetoothHeadset.STATE_CONNECTED)
   1408                         && (bluetoothAudioState == BluetoothHeadset.STATE_AUDIO_CONNECTED));
   1409 
   1410             case RINGING:
   1411                 // If an incoming call is ringing, we're *not* yet routing
   1412                 // audio to the headset (since there's no in-call audio
   1413                 // yet!)  In this case, if a bluetooth headset is
   1414                 // connected at all, we assume that it'll become active
   1415                 // once the user answers the phone.
   1416                 return (bluetoothState == BluetoothHeadset.STATE_CONNECTED);
   1417 
   1418             default:  // Presumably IDLE
   1419                 return false;
   1420         }
   1421     }
   1422 
   1423 
   1424     /**
   1425      * Receiver for misc intent broadcasts the Phone app cares about.
   1426      */
   1427     private class PhoneAppBroadcastReceiver extends BroadcastReceiver {
   1428         @Override
   1429         public void onReceive(Context context, Intent intent) {
   1430             String action = intent.getAction();
   1431             if (action.equals(Intent.ACTION_AIRPLANE_MODE_CHANGED)) {
   1432                 boolean enabled = System.getInt(getContentResolver(),
   1433                         System.AIRPLANE_MODE_ON, 0) == 0;
   1434                 phone.setRadioPower(enabled);
   1435             } else if (action.equals(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED)) {
   1436                 mBluetoothHeadsetState = intent.getIntExtra(BluetoothHeadset.EXTRA_STATE,
   1437                                                           BluetoothHeadset.STATE_DISCONNECTED);
   1438                 if (VDBG) Log.d(LOG_TAG, "mReceiver: HEADSET_STATE_CHANGED_ACTION");
   1439                 if (VDBG) Log.d(LOG_TAG, "==> new state: " + mBluetoothHeadsetState);
   1440                 updateBluetoothIndication(true);  // Also update any visible UI if necessary
   1441             } else if (action.equals(BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED)) {
   1442                 mBluetoothHeadsetAudioState =
   1443                         intent.getIntExtra(BluetoothHeadset.EXTRA_STATE,
   1444                                            BluetoothHeadset.STATE_AUDIO_DISCONNECTED);
   1445                 if (VDBG) Log.d(LOG_TAG, "mReceiver: HEADSET_AUDIO_STATE_CHANGED_ACTION");
   1446                 if (VDBG) Log.d(LOG_TAG, "==> new state: " + mBluetoothHeadsetAudioState);
   1447                 updateBluetoothIndication(true);  // Also update any visible UI if necessary
   1448             } else if (action.equals(TelephonyIntents.ACTION_ANY_DATA_CONNECTION_STATE_CHANGED)) {
   1449                 if (VDBG) Log.d(LOG_TAG, "mReceiver: ACTION_ANY_DATA_CONNECTION_STATE_CHANGED");
   1450                 if (VDBG) Log.d(LOG_TAG, "- state: " + intent.getStringExtra(Phone.STATE_KEY));
   1451                 if (VDBG) Log.d(LOG_TAG, "- reason: "
   1452                                 + intent.getStringExtra(Phone.STATE_CHANGE_REASON_KEY));
   1453 
   1454                 // The "data disconnected due to roaming" notification is shown
   1455                 // if (a) you have the "data roaming" feature turned off, and
   1456                 // (b) you just lost data connectivity because you're roaming.
   1457                 boolean disconnectedDueToRoaming =
   1458                         !phone.getDataRoamingEnabled()
   1459                         && "DISCONNECTED".equals(intent.getStringExtra(Phone.STATE_KEY))
   1460                         && Phone.REASON_ROAMING_ON.equals(
   1461                             intent.getStringExtra(Phone.STATE_CHANGE_REASON_KEY));
   1462                 mHandler.sendEmptyMessage(disconnectedDueToRoaming
   1463                                           ? EVENT_DATA_ROAMING_DISCONNECTED
   1464                                           : EVENT_DATA_ROAMING_OK);
   1465             } else if (action.equals(Intent.ACTION_HEADSET_PLUG)) {
   1466                 if (VDBG) Log.d(LOG_TAG, "mReceiver: ACTION_HEADSET_PLUG");
   1467                 if (VDBG) Log.d(LOG_TAG, "    state: " + intent.getIntExtra("state", 0));
   1468                 if (VDBG) Log.d(LOG_TAG, "    name: " + intent.getStringExtra("name"));
   1469                 mIsHeadsetPlugged = (intent.getIntExtra("state", 0) == 1);
   1470                 mHandler.sendMessage(mHandler.obtainMessage(EVENT_WIRED_HEADSET_PLUG, 0));
   1471             } else if (action.equals(Intent.ACTION_BATTERY_LOW)) {
   1472                 if (VDBG) Log.d(LOG_TAG, "mReceiver: ACTION_BATTERY_LOW");
   1473                 notifier.sendBatteryLow();  // Play a warning tone if in-call
   1474             } else if ((action.equals(TelephonyIntents.ACTION_SIM_STATE_CHANGED)) &&
   1475                     (mPUKEntryActivity != null)) {
   1476                 // if an attempt to un-PUK-lock the device was made, while we're
   1477                 // receiving this state change notification, notify the handler.
   1478                 // NOTE: This is ONLY triggered if an attempt to un-PUK-lock has
   1479                 // been attempted.
   1480                 mHandler.sendMessage(mHandler.obtainMessage(EVENT_SIM_STATE_CHANGED,
   1481                         intent.getStringExtra(IccCard.INTENT_KEY_ICC_STATE)));
   1482             } else if (action.equals(TelephonyIntents.ACTION_RADIO_TECHNOLOGY_CHANGED)) {
   1483                 String newPhone = intent.getStringExtra(Phone.PHONE_NAME_KEY);
   1484                 Log.d(LOG_TAG, "Radio technology switched. Now " + newPhone + " is active.");
   1485                 initForNewRadioTechnology();
   1486             } else if (action.equals(TelephonyIntents.ACTION_SERVICE_STATE_CHANGED)) {
   1487                 handleServiceStateChanged(intent);
   1488             } else if (action.equals(TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED)) {
   1489                 if (TelephonyCapabilities.supportsEcm(phone)) {
   1490                     Log.d(LOG_TAG, "Emergency Callback Mode arrived in PhoneApp.");
   1491                     // Start Emergency Callback Mode service
   1492                     if (intent.getBooleanExtra("phoneinECMState", false)) {
   1493                         context.startService(new Intent(context,
   1494                                 EmergencyCallbackModeService.class));
   1495                     }
   1496                 } else {
   1497                     // It doesn't make sense to get ACTION_EMERGENCY_CALLBACK_MODE_CHANGED
   1498                     // on a device that doesn't support ECM in the first place.
   1499                     Log.e(LOG_TAG, "Got ACTION_EMERGENCY_CALLBACK_MODE_CHANGED, "
   1500                           + "but ECM isn't supported for phone: " + phone.getPhoneName());
   1501                 }
   1502             } else if (action.equals(Intent.ACTION_DOCK_EVENT)) {
   1503                 mDockState = intent.getIntExtra(Intent.EXTRA_DOCK_STATE,
   1504                         Intent.EXTRA_DOCK_STATE_UNDOCKED);
   1505                 if (VDBG) Log.d(LOG_TAG, "ACTION_DOCK_EVENT -> mDockState = " + mDockState);
   1506                 mHandler.sendMessage(mHandler.obtainMessage(EVENT_DOCK_STATE_CHANGED, 0));
   1507             } else if (action.equals(TtyIntent.TTY_PREFERRED_MODE_CHANGE_ACTION)) {
   1508                 mPreferredTtyMode = intent.getIntExtra(TtyIntent.TTY_PREFFERED_MODE,
   1509                                                        Phone.TTY_MODE_OFF);
   1510                 if (VDBG) Log.d(LOG_TAG, "mReceiver: TTY_PREFERRED_MODE_CHANGE_ACTION");
   1511                 if (VDBG) Log.d(LOG_TAG, "    mode: " + mPreferredTtyMode);
   1512                 mHandler.sendMessage(mHandler.obtainMessage(EVENT_TTY_PREFERRED_MODE_CHANGED, 0));
   1513             } else if (action.equals(AudioManager.RINGER_MODE_CHANGED_ACTION)) {
   1514                 int ringerMode = intent.getIntExtra(AudioManager.EXTRA_RINGER_MODE,
   1515                         AudioManager.RINGER_MODE_NORMAL);
   1516                 if (ringerMode == AudioManager.RINGER_MODE_SILENT) {
   1517                     notifier.silenceRinger();
   1518                 }
   1519             }
   1520         }
   1521     }
   1522 
   1523     /**
   1524      * Broadcast receiver for the ACTION_MEDIA_BUTTON broadcast intent.
   1525      *
   1526      * This functionality isn't lumped in with the other intents in
   1527      * PhoneAppBroadcastReceiver because we instantiate this as a totally
   1528      * separate BroadcastReceiver instance, since we need to manually
   1529      * adjust its IntentFilter's priority (to make sure we get these
   1530      * intents *before* the media player.)
   1531      */
   1532     private class MediaButtonBroadcastReceiver extends BroadcastReceiver {
   1533         @Override
   1534         public void onReceive(Context context, Intent intent) {
   1535             KeyEvent event = (KeyEvent) intent.getParcelableExtra(Intent.EXTRA_KEY_EVENT);
   1536             if (VDBG) Log.d(LOG_TAG,
   1537                            "MediaButtonBroadcastReceiver.onReceive()...  event = " + event);
   1538             if ((event != null)
   1539                 && (event.getKeyCode() == KeyEvent.KEYCODE_HEADSETHOOK)) {
   1540                 if (VDBG) Log.d(LOG_TAG, "MediaButtonBroadcastReceiver: HEADSETHOOK");
   1541                 boolean consumed = PhoneUtils.handleHeadsetHook(phone, event);
   1542                 if (VDBG) Log.d(LOG_TAG, "==> handleHeadsetHook(): consumed = " + consumed);
   1543                 if (consumed) {
   1544                     // If a headset is attached and the press is consumed, also update
   1545                     // any UI items (such as an InCallScreen mute button) that may need to
   1546                     // be updated if their state changed.
   1547                     updateInCallScreen();  // Has no effect if the InCallScreen isn't visible
   1548                     abortBroadcast();
   1549                 }
   1550             } else {
   1551                 if (mCM.getState() != Phone.State.IDLE) {
   1552                     // If the phone is anything other than completely idle,
   1553                     // then we consume and ignore any media key events,
   1554                     // Otherwise it is too easy to accidentally start
   1555                     // playing music while a phone call is in progress.
   1556                     if (VDBG) Log.d(LOG_TAG, "MediaButtonBroadcastReceiver: consumed");
   1557                     abortBroadcast();
   1558                 }
   1559             }
   1560         }
   1561     }
   1562 
   1563     private void handleServiceStateChanged(Intent intent) {
   1564         /**
   1565          * This used to handle updating EriTextWidgetProvider this routine
   1566          * and and listening for ACTION_SERVICE_STATE_CHANGED intents could
   1567          * be removed. But leaving just in case it might be needed in the near
   1568          * future.
   1569          */
   1570 
   1571         // If service just returned, start sending out the queued messages
   1572         ServiceState ss = ServiceState.newFromBundle(intent.getExtras());
   1573 
   1574         if (ss != null) {
   1575             int state = ss.getState();
   1576             notificationMgr.updateNetworkSelection(state);
   1577         }
   1578     }
   1579 
   1580     public boolean isOtaCallInActiveState() {
   1581         boolean otaCallActive = false;
   1582         if (mInCallScreen != null) {
   1583             otaCallActive = mInCallScreen.isOtaCallInActiveState();
   1584         }
   1585         if (VDBG) Log.d(LOG_TAG, "- isOtaCallInActiveState " + otaCallActive);
   1586         return otaCallActive;
   1587     }
   1588 
   1589     public boolean isOtaCallInEndState() {
   1590         boolean otaCallEnded = false;
   1591         if (mInCallScreen != null) {
   1592             otaCallEnded = mInCallScreen.isOtaCallInEndState();
   1593         }
   1594         if (VDBG) Log.d(LOG_TAG, "- isOtaCallInEndState " + otaCallEnded);
   1595         return otaCallEnded;
   1596     }
   1597 
   1598     // it is safe to call clearOtaState() even if the InCallScreen isn't active
   1599     public void clearOtaState() {
   1600         if (DBG) Log.d(LOG_TAG, "- clearOtaState ...");
   1601         if ((mInCallScreen != null)
   1602                 && (otaUtils != null)) {
   1603             otaUtils.cleanOtaScreen(true);
   1604             if (DBG) Log.d(LOG_TAG, "  - clearOtaState clears OTA screen");
   1605         }
   1606     }
   1607 
   1608     // it is safe to call dismissOtaDialogs() even if the InCallScreen isn't active
   1609     public void dismissOtaDialogs() {
   1610         if (DBG) Log.d(LOG_TAG, "- dismissOtaDialogs ...");
   1611         if ((mInCallScreen != null)
   1612                 && (otaUtils != null)) {
   1613             otaUtils.dismissAllOtaDialogs();
   1614             if (DBG) Log.d(LOG_TAG, "  - dismissOtaDialogs clears OTA dialogs");
   1615         }
   1616     }
   1617 
   1618     // it is safe to call clearInCallScreenMode() even if the InCallScreen isn't active
   1619     public void clearInCallScreenMode() {
   1620         if (DBG) Log.d(LOG_TAG, "- clearInCallScreenMode ...");
   1621         if (mInCallScreen != null) {
   1622             mInCallScreen.resetInCallScreenMode();
   1623         }
   1624     }
   1625 
   1626     /**
   1627      * Force the in-call UI to refresh itself, if it's currently visible.
   1628      *
   1629      * This method can be used any time there's a state change anywhere in
   1630      * the phone app that needs to be reflected in the onscreen UI.
   1631      *
   1632      * Note that it's *not* necessary to manually refresh the in-call UI
   1633      * (via this method) for regular telephony state changes like
   1634      * DIALING -> ALERTING -> ACTIVE, since the InCallScreen already
   1635      * listens for those state changes itself.
   1636      *
   1637      * This method does *not* force the in-call UI to come up if it's not
   1638      * already visible.  To do that, use displayCallScreen().
   1639      */
   1640     /* package */ void updateInCallScreen() {
   1641         if (DBG) Log.d(LOG_TAG, "- updateInCallScreen()...");
   1642         if (mInCallScreen != null) {
   1643             // Post an updateScreen() request.  Note that the
   1644             // updateScreen() call will end up being a no-op if the
   1645             // InCallScreen isn't the foreground activity.
   1646             mInCallScreen.requestUpdateScreen();
   1647         }
   1648     }
   1649 
   1650     private void handleQueryTTYModeResponse(Message msg) {
   1651         AsyncResult ar = (AsyncResult) msg.obj;
   1652         if (ar.exception != null) {
   1653             if (DBG) Log.d(LOG_TAG, "handleQueryTTYModeResponse: Error getting TTY state.");
   1654         } else {
   1655             if (DBG) Log.d(LOG_TAG,
   1656                            "handleQueryTTYModeResponse: TTY enable state successfully queried.");
   1657 
   1658             int ttymode = ((int[]) ar.result)[0];
   1659             if (DBG) Log.d(LOG_TAG, "handleQueryTTYModeResponse:ttymode=" + ttymode);
   1660 
   1661             Intent ttyModeChanged = new Intent(TtyIntent.TTY_ENABLED_CHANGE_ACTION);
   1662             ttyModeChanged.putExtra("ttyEnabled", ttymode != Phone.TTY_MODE_OFF);
   1663             sendBroadcast(ttyModeChanged);
   1664 
   1665             String audioTtyMode;
   1666             switch (ttymode) {
   1667             case Phone.TTY_MODE_FULL:
   1668                 audioTtyMode = "tty_full";
   1669                 break;
   1670             case Phone.TTY_MODE_VCO:
   1671                 audioTtyMode = "tty_vco";
   1672                 break;
   1673             case Phone.TTY_MODE_HCO:
   1674                 audioTtyMode = "tty_hco";
   1675                 break;
   1676             case Phone.TTY_MODE_OFF:
   1677             default:
   1678                 audioTtyMode = "tty_off";
   1679                 break;
   1680             }
   1681             AudioManager audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
   1682             audioManager.setParameters("tty_mode="+audioTtyMode);
   1683         }
   1684     }
   1685 
   1686     private void handleSetTTYModeResponse(Message msg) {
   1687         AsyncResult ar = (AsyncResult) msg.obj;
   1688 
   1689         if (ar.exception != null) {
   1690             if (DBG) Log.d (LOG_TAG,
   1691                     "handleSetTTYModeResponse: Error setting TTY mode, ar.exception"
   1692                     + ar.exception);
   1693         }
   1694         phone.queryTTYMode(mHandler.obtainMessage(EVENT_TTY_MODE_GET));
   1695     }
   1696 
   1697     /* package */ void clearUserActivityTimeout() {
   1698         try {
   1699             mPowerManagerService.clearUserActivityTimeout(SystemClock.uptimeMillis(),
   1700                     10*1000 /* 10 sec */);
   1701         } catch (RemoteException ex) {
   1702             // System process is dead.
   1703         }
   1704     }
   1705 
   1706     /**
   1707      * "Call origin" may be used by Contacts app to specify where the phone call comes from.
   1708      * Currently, the only permitted value for this extra is {@link #ALLOWED_EXTRA_CALL_ORIGIN}.
   1709      * Any other value will be ignored, to make sure that malicious apps can't trick the in-call
   1710      * UI into launching some random other app after a call ends.
   1711      *
   1712      * TODO: make this more generic. Note that we should let the "origin" specify its package
   1713      * while we are now assuming it is "com.android.contacts"
   1714      */
   1715     public static final String EXTRA_CALL_ORIGIN = "com.android.phone.CALL_ORIGIN";
   1716     private static final String DEFAULT_CALL_ORIGIN_PACKAGE = "com.android.contacts";
   1717     private static final String ALLOWED_EXTRA_CALL_ORIGIN =
   1718             "com.android.contacts.activities.DialtactsActivity";
   1719 
   1720     public void setLatestActiveCallOrigin(String callOrigin) {
   1721         inCallUiState.latestActiveCallOrigin = callOrigin;
   1722     }
   1723 
   1724     /**
   1725      * @return Intent which will be used when in-call UI is shown and the phone call is hang up.
   1726      * By default CallLog screen will be introduced, but the destination may change depending on
   1727      * its latest call origin state.
   1728      */
   1729     public Intent createPhoneEndIntentUsingCallOrigin() {
   1730         if (TextUtils.equals(inCallUiState.latestActiveCallOrigin, ALLOWED_EXTRA_CALL_ORIGIN)) {
   1731             if (VDBG) Log.d(LOG_TAG, "Valid latestActiveCallOrigin("
   1732                     + inCallUiState.latestActiveCallOrigin + ") was found. "
   1733                     + "Go back to the previous screen.");
   1734             // Right now we just launch the Activity which launched in-call UI. Note that we're
   1735             // assuming the origin is from "com.android.contacts", which may be incorrect in the
   1736             // future.
   1737             final Intent intent = new Intent();
   1738             intent.setClassName(DEFAULT_CALL_ORIGIN_PACKAGE, inCallUiState.latestActiveCallOrigin);
   1739             return intent;
   1740         } else {
   1741             if (VDBG) Log.d(LOG_TAG, "Current latestActiveCallOrigin ("
   1742                     + inCallUiState.latestActiveCallOrigin + ") is not valid. "
   1743                     + "Just use CallLog as a default destination.");
   1744             return PhoneApp.createCallLogIntent();
   1745         }
   1746     }
   1747 }
   1748