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