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