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