PhoneApp.java revision 6a8928a7265b6586b561e60ee93b23f5fa6f30ea
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        if (phoneIsCdma) {
501            int settingsTtyMode = android.provider.Settings.Secure.getInt(
502                    phone.getContext().getContentResolver(),
503                    android.provider.Settings.Secure.PREFERRED_TTY_MODE,
504                    Phone.TTY_MODE_OFF);
505            phone.setTTYMode(settingsTtyMode, null);
506        }
507   }
508
509    @Override
510    public void onConfigurationChanged(Configuration newConfig) {
511        if (newConfig.hardKeyboardHidden == Configuration.HARDKEYBOARDHIDDEN_NO) {
512            mIsHardKeyboardOpen = true;
513        } else {
514            mIsHardKeyboardOpen = false;
515        }
516
517        // Update the Proximity sensor based on keyboard state
518        updateProximitySensorMode(phone.getState());
519        super.onConfigurationChanged(newConfig);
520    }
521
522    /**
523     * Returns the singleton instance of the PhoneApp.
524     */
525    static PhoneApp getInstance() {
526        return sMe;
527    }
528
529    Ringer getRinger() {
530        return ringer;
531    }
532
533    BluetoothHandsfree getBluetoothHandsfree() {
534        return mBtHandsfree;
535    }
536
537    static Intent createCallLogIntent() {
538        Intent  intent = new Intent(Intent.ACTION_VIEW, null);
539        intent.setType("vnd.android.cursor.dir/calls");
540        return intent;
541    }
542
543    /**
544     * Return an Intent that can be used to bring up the in-call screen.
545     *
546     * This intent can only be used from within the Phone app, since the
547     * InCallScreen is not exported from our AndroidManifest.
548     */
549    /* package */ static Intent createInCallIntent() {
550        Intent intent = new Intent(Intent.ACTION_MAIN, null);
551        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
552                | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
553                | Intent.FLAG_ACTIVITY_NO_USER_ACTION);
554        intent.setClassName("com.android.phone", getCallScreenClassName());
555        return intent;
556    }
557
558    /**
559     * Variation of createInCallIntent() that also specifies whether the
560     * DTMF dialpad should be initially visible when the InCallScreen
561     * comes up.
562     */
563    /* package */ static Intent createInCallIntent(boolean showDialpad) {
564        Intent intent = createInCallIntent();
565        intent.putExtra(InCallScreen.SHOW_DIALPAD_EXTRA, showDialpad);
566        return intent;
567    }
568
569    static String getCallScreenClassName() {
570        return InCallScreen.class.getName();
571    }
572
573    /**
574     * Starts the InCallScreen Activity.
575     */
576    void displayCallScreen() {
577        if (VDBG) Log.d(LOG_TAG, "displayCallScreen()...");
578        startActivity(createInCallIntent());
579        Profiler.callScreenRequested();
580    }
581
582    /**
583     * Helper function to check for one special feature of the CALL key:
584     * Normally, when the phone is idle, CALL takes you to the call log
585     * (see the handler for KEYCODE_CALL in PhoneWindow.onKeyUp().)
586     * But if the phone is in use (either off-hook or ringing) we instead
587     * handle the CALL button by taking you to the in-call UI.
588     *
589     * @return true if we intercepted the CALL keypress (i.e. the phone
590     *              was in use)
591     *
592     * @see DialerActivity#onCreate
593     */
594    boolean handleInCallOrRinging() {
595        if (phone.getState() != Phone.State.IDLE) {
596            // Phone is OFFHOOK or RINGING.
597            if (DBG) Log.v(LOG_TAG,
598                           "handleInCallOrRinging: show call screen");
599            displayCallScreen();
600            return true;
601        }
602        return false;
603    }
604
605    boolean isSimPinEnabled() {
606        return mIsSimPinEnabled;
607    }
608
609    boolean authenticateAgainstCachedSimPin(String pin) {
610        return (mCachedSimPin != null && mCachedSimPin.equals(pin));
611    }
612
613    void setCachedSimPin(String pin) {
614        mCachedSimPin = pin;
615    }
616
617    void setInCallScreenInstance(InCallScreen inCallScreen) {
618        mInCallScreen = inCallScreen;
619    }
620
621    /**
622     * @return true if the in-call UI is running as the foreground
623     * activity.  (In other words, from the perspective of the
624     * InCallScreen activity, return true between onResume() and
625     * onPause().)
626     *
627     * Note this method will return false if the screen is currently off,
628     * even if the InCallScreen *was* in the foreground just before the
629     * screen turned off.  (This is because the foreground activity is
630     * always "paused" while the screen is off.)
631     */
632    boolean isShowingCallScreen() {
633        if (mInCallScreen == null) return false;
634        return mInCallScreen.isForegroundActivity();
635    }
636
637    /**
638     * Dismisses the in-call UI.
639     *
640     * This also ensures that you won't be able to get back to the in-call
641     * UI via the BACK button (since this call removes the InCallScreen
642     * from the activity history.)
643     * For OTA Call, it call InCallScreen api to handle OTA Call End scenario
644     * to display OTA Call End screen.
645     */
646    void dismissCallScreen() {
647        if (mInCallScreen != null) {
648            if (mInCallScreen.isOtaCallInActiveState()
649                    || mInCallScreen.isOtaCallInEndState()
650                    || ((cdmaOtaScreenState != null)
651                    && (cdmaOtaScreenState.otaScreenState
652                            != CdmaOtaScreenState.OtaScreenState.OTA_STATUS_UNDEFINED))) {
653                // TODO(Moto): During OTA Call, display should not become dark to
654                // allow user to see OTA UI update. Phone app needs to hold a SCREEN_DIM_WAKE_LOCK
655                // wake lock during the entire OTA call.
656                wakeUpScreen();
657                // If InCallScreen is not in foreground we resume it to show the OTA call end screen
658                // Fire off the InCallScreen intent
659                displayCallScreen();
660
661                mInCallScreen.handleOtaCallEnd();
662                return;
663            } else {
664                mInCallScreen.finish();
665            }
666        }
667    }
668
669    /**
670     * Handle OTA events
671     *
672     * When OTA call is active and display becomes dark, then CallNotifier will
673     * handle OTA Events by calling this api which then calls OtaUtil function.
674     */
675    void handleOtaEvents(Message msg) {
676
677        if (DBG) Log.d(LOG_TAG, "Enter handleOtaEvents");
678        if ((mInCallScreen != null) && (!isShowingCallScreen())) {
679            if (mInCallScreen.otaUtils != null) {
680                mInCallScreen.otaUtils.onOtaProvisionStatusChanged((AsyncResult) msg.obj);
681            }
682        }
683    }
684
685
686    /**
687     * Sets the activity responsible for un-PUK-blocking the device
688     * so that we may close it when we receive a positive result.
689     * mPUKEntryActivity is also used to indicate to the device that
690     * we are trying to un-PUK-lock the phone. In other words, iff
691     * it is NOT null, then we are trying to unlock and waiting for
692     * the SIM to move to READY state.
693     *
694     * @param activity is the activity to close when PUK has
695     * finished unlocking. Can be set to null to indicate the unlock
696     * or SIM READYing process is over.
697     */
698    void setPukEntryActivity(Activity activity) {
699        mPUKEntryActivity = activity;
700    }
701
702    Activity getPUKEntryActivity() {
703        return mPUKEntryActivity;
704    }
705
706    /**
707     * Sets the dialog responsible for notifying the user of un-PUK-
708     * blocking - SIM READYing progress, so that we may dismiss it
709     * when we receive a positive result.
710     *
711     * @param dialog indicates the progress dialog informing the user
712     * of the state of the device.  Dismissed upon completion of
713     * READYing process
714     */
715    void setPukEntryProgressDialog(ProgressDialog dialog) {
716        mPUKEntryProgressDialog = dialog;
717    }
718
719    ProgressDialog getPUKEntryProgressDialog() {
720        return mPUKEntryProgressDialog;
721    }
722
723    /**
724     * Disables the status bar.  This is used by the phone app when in-call UI is active.
725     *
726     * Any call to this method MUST be followed (eventually)
727     * by a corresponding reenableStatusBar() call.
728     */
729    /* package */ void disableStatusBar() {
730        if (DBG) Log.d(LOG_TAG, "disable status bar");
731        synchronized (this) {
732            if (mStatusBarDisableCount++ == 0) {
733               if (DBG)  Log.d(LOG_TAG, "StatusBarManager.DISABLE_EXPAND");
734                mStatusBarManager.disable(StatusBarManager.DISABLE_EXPAND);
735            }
736        }
737    }
738
739    /**
740     * Re-enables the status bar after a previous disableStatusBar() call.
741     *
742     * Any call to this method MUST correspond to (i.e. be balanced with)
743     * a previous disableStatusBar() call.
744     */
745    /* package */ void reenableStatusBar() {
746        if (DBG) Log.d(LOG_TAG, "re-enable status bar");
747        synchronized (this) {
748            if (mStatusBarDisableCount > 0) {
749                if (--mStatusBarDisableCount == 0) {
750                    if (DBG) Log.d(LOG_TAG, "StatusBarManager.DISABLE_NONE");
751                    mStatusBarManager.disable(StatusBarManager.DISABLE_NONE);
752                }
753            } else {
754                Log.e(LOG_TAG, "mStatusBarDisableCount is already zero");
755            }
756        }
757    }
758
759    /**
760     * Controls how quickly the screen times out.
761     *
762     * The poke lock controls how long it takes before the screen powers
763     * down, and therefore has no immediate effect when the current
764     * WakeState (see {@link PhoneApp#requestWakeState}) is FULL.
765     * If we're in a state where the screen *is* allowed to turn off,
766     * though, the poke lock will determine the timeout interval (long or
767     * short).
768     *
769     * @param shortPokeLock tells the device the timeout duration to use
770     * before going to sleep
771     * {@link com.android.server.PowerManagerService#SHORT_KEYLIGHT_DELAY}.
772     */
773    /* package */ void setScreenTimeout(ScreenTimeoutDuration duration) {
774        if (VDBG) Log.d(LOG_TAG, "setScreenTimeout(" + duration + ")...");
775
776        // make sure we don't set the poke lock repeatedly so that we
777        // avoid triggering the userActivity calls in
778        // PowerManagerService.setPokeLock().
779        if (duration == mScreenTimeoutDuration) {
780            return;
781        }
782        // stick with default timeout if we are using the proximity sensor
783        if (proximitySensorModeEnabled()) {
784            return;
785        }
786        mScreenTimeoutDuration = duration;
787        updatePokeLock();
788    }
789
790    /**
791     * Update the state of the poke lock held by the phone app,
792     * based on the current desired screen timeout and the
793     * current "ignore user activity on touch" flag.
794     */
795    private void updatePokeLock() {
796        // This is kind of convoluted, but the basic thing to remember is
797        // that the poke lock just sends a message to the screen to tell
798        // it to stay on for a while.
799        // The default is 0, for a long timeout and should be set that way
800        // when we are heading back into a the keyguard / screen off
801        // state, and also when we're trying to keep the screen alive
802        // while ringing.  We'll also want to ignore the cheek events
803        // regardless of the timeout duration.
804        // The short timeout is really used whenever we want to give up
805        // the screen lock, such as when we're in call.
806        int pokeLockSetting = LocalPowerManager.POKE_LOCK_IGNORE_CHEEK_EVENTS;
807        switch (mScreenTimeoutDuration) {
808            case SHORT:
809                // Set the poke lock to timeout the display after a short
810                // timeout (5s). This ensures that the screen goes to sleep
811                // as soon as acceptably possible after we the wake lock
812                // has been released.
813                pokeLockSetting |= LocalPowerManager.POKE_LOCK_SHORT_TIMEOUT;
814                break;
815
816            case MEDIUM:
817                // Set the poke lock to timeout the display after a medium
818                // timeout (15s). This ensures that the screen goes to sleep
819                // as soon as acceptably possible after we the wake lock
820                // has been released.
821                pokeLockSetting |= LocalPowerManager.POKE_LOCK_MEDIUM_TIMEOUT;
822                break;
823
824            case DEFAULT:
825            default:
826                // set the poke lock to timeout the display after a long
827                // delay by default.
828                // TODO: it may be nice to be able to disable cheek presses
829                // for long poke locks (emergency dialer, for instance).
830                break;
831        }
832
833        if (mIgnoreTouchUserActivity) {
834            pokeLockSetting |= LocalPowerManager.POKE_LOCK_IGNORE_TOUCH_AND_CHEEK_EVENTS;
835        }
836
837        // Send the request
838        try {
839            mPowerManagerService.setPokeLock(pokeLockSetting, mPokeLockToken, LOG_TAG);
840        } catch (RemoteException e) {
841            Log.w(LOG_TAG, "mPowerManagerService.setPokeLock() failed: " + e);
842        }
843    }
844
845    /**
846     * Controls whether or not the screen is allowed to sleep.
847     *
848     * Once sleep is allowed (WakeState is SLEEP), it will rely on the
849     * settings for the poke lock to determine when to timeout and let
850     * the device sleep {@link PhoneApp#setScreenTimeout}.
851     *
852     * @param ws tells the device to how to wake.
853     */
854    /* package */ void requestWakeState(WakeState ws) {
855        if (VDBG) Log.d(LOG_TAG, "requestWakeState(" + ws + ")...");
856        synchronized (this) {
857            if (mWakeState != ws) {
858                switch (ws) {
859                    case PARTIAL:
860                        // acquire the processor wake lock, and release the FULL
861                        // lock if it is being held.
862                        mPartialWakeLock.acquire();
863                        if (mWakeLock.isHeld()) {
864                            mWakeLock.release();
865                        }
866                        break;
867                    case FULL:
868                        // acquire the full wake lock, and release the PARTIAL
869                        // lock if it is being held.
870                        mWakeLock.acquire();
871                        if (mPartialWakeLock.isHeld()) {
872                            mPartialWakeLock.release();
873                        }
874                        break;
875                    case SLEEP:
876                    default:
877                        // release both the PARTIAL and FULL locks.
878                        if (mWakeLock.isHeld()) {
879                            mWakeLock.release();
880                        }
881                        if (mPartialWakeLock.isHeld()) {
882                            mPartialWakeLock.release();
883                        }
884                        break;
885                }
886                mWakeState = ws;
887            }
888        }
889    }
890
891    /**
892     * If we are not currently keeping the screen on, then poke the power
893     * manager to wake up the screen for the user activity timeout duration.
894     */
895    /* package */ void wakeUpScreen() {
896        synchronized (this) {
897            if (mWakeState == WakeState.SLEEP) {
898                if (DBG) Log.d(LOG_TAG, "pulse screen lock");
899                try {
900                    mPowerManagerService.userActivityWithForce(SystemClock.uptimeMillis(), false, true);
901                } catch (RemoteException ex) {
902                    // Ignore -- the system process is dead.
903                }
904            }
905        }
906    }
907
908    /**
909     * Sets the wake state and screen timeout based on the current state
910     * of the phone, and the current state of the in-call UI.
911     *
912     * This method is a "UI Policy" wrapper around
913     * {@link PhoneApp#requestWakeState} and {@link PhoneApp#setScreenTimeout}.
914     *
915     * It's safe to call this method regardless of the state of the Phone
916     * (e.g. whether or not it's idle), and regardless of the state of the
917     * Phone UI (e.g. whether or not the InCallScreen is active.)
918     */
919    /* package */ void updateWakeState() {
920        Phone.State state = phone.getState();
921
922        // True if the in-call UI is the foreground activity.
923        // (Note this will be false if the screen is currently off,
924        // since in that case *no* activity is in the foreground.)
925        boolean isShowingCallScreen = isShowingCallScreen();
926
927        // True if the InCallScreen's DTMF dialer is currently opened.
928        // (Note this does NOT imply whether or not the InCallScreen
929        // itself is visible.)
930        boolean isDialerOpened = (mInCallScreen != null) && mInCallScreen.isDialerOpened();
931
932        // True if the speakerphone is in use.  (If so, we *always* use
933        // the default timeout.  Since the user is obviously not holding
934        // the phone up to his/her face, we don't need to worry about
935        // false touches, and thus don't need to turn the screen off so
936        // aggressively.)
937        // Note that we need to make a fresh call to this method any
938        // time the speaker state changes.  (That happens in
939        // PhoneUtils.turnOnSpeaker().)
940        boolean isSpeakerInUse = (state == Phone.State.OFFHOOK) && PhoneUtils.isSpeakerOn(this);
941
942        // TODO (bug 1440854): The screen timeout *might* also need to
943        // depend on the bluetooth state, but this isn't as clear-cut as
944        // the speaker state (since while using BT it's common for the
945        // user to put the phone straight into a pocket, in which case the
946        // timeout should probably still be short.)
947
948        if (DBG) Log.d(LOG_TAG, "updateWakeState: callscreen " + isShowingCallScreen
949                       + ", dialer " + isDialerOpened
950                       + ", speaker " + isSpeakerInUse + "...");
951
952        //
953        // (1) Set the screen timeout.
954        //
955        // Note that the "screen timeout" value we determine here is
956        // meaningless if the screen is forced on (see (2) below.)
957        //
958        if (!isShowingCallScreen || isSpeakerInUse) {
959            // Use the system-wide default timeout.
960            setScreenTimeout(ScreenTimeoutDuration.DEFAULT);
961        } else {
962            // We're on the in-call screen, and *not* using the speakerphone.
963            if (isDialerOpened) {
964                // The DTMF dialpad is up.  This case is special because
965                // the in-call UI has its own "touch lock" mechanism to
966                // disable the dialpad after a very short amount of idle
967                // time (to avoid false touches from the user's face while
968                // in-call.)
969                //
970                // In this case the *physical* screen just uses the
971                // system-wide default timeout.
972                setScreenTimeout(ScreenTimeoutDuration.DEFAULT);
973            } else {
974                // We're on the in-call screen, and not using the DTMF dialpad.
975                // There's actually no touchable UI onscreen at all in
976                // this state.  Also, the user is (most likely) not
977                // looking at the screen at all, since they're probably
978                // holding the phone up to their face.  Here we use a
979                // special screen timeout value specific to the in-call
980                // screen, purely to save battery life.
981                setScreenTimeout(ScreenTimeoutDuration.MEDIUM);
982            }
983        }
984
985        //
986        // (2) Decide whether to force the screen on or not.
987        //
988        // Force the screen to be on if the phone is ringing or dialing,
989        // or if we're displaying the "Call ended" UI for a connection in
990        // the "disconnected" state.
991        //
992        boolean isRinging = (state == Phone.State.RINGING);
993        boolean isDialing = (phone.getForegroundCall().getState() == Call.State.DIALING);
994        boolean showingDisconnectedConnection =
995                PhoneUtils.hasDisconnectedConnections(phone) && isShowingCallScreen;
996        boolean keepScreenOn = isRinging || isDialing || showingDisconnectedConnection;
997        if (DBG) Log.d(LOG_TAG, "updateWakeState: keepScreenOn = " + keepScreenOn
998                       + " (isRinging " + isRinging
999                       + ", isDialing " + isDialing
1000                       + ", showingDisc " + showingDisconnectedConnection + ")");
1001        // keepScreenOn == true means we'll hold a full wake lock:
1002        requestWakeState(keepScreenOn ? WakeState.FULL : WakeState.SLEEP);
1003    }
1004
1005    /**
1006     * Wrapper around the PowerManagerService.preventScreenOn() API.
1007     * This allows the in-call UI to prevent the screen from turning on
1008     * even if a subsequent call to updateWakeState() causes us to acquire
1009     * a full wake lock.
1010     */
1011    /* package */ void preventScreenOn(boolean prevent) {
1012        if (VDBG) Log.d(LOG_TAG, "- preventScreenOn(" + prevent + ")...");
1013        try {
1014            mPowerManagerService.preventScreenOn(prevent);
1015        } catch (RemoteException e) {
1016            Log.w(LOG_TAG, "mPowerManagerService.preventScreenOn() failed: " + e);
1017        }
1018    }
1019
1020    /**
1021     * Sets or clears the flag that tells the PowerManager that touch
1022     * (and cheek) events should NOT be considered "user activity".
1023     *
1024     * Since the in-call UI is totally insensitive to touch in most
1025     * states, we set this flag whenever the InCallScreen is in the
1026     * foreground.  (Otherwise, repeated unintentional touches could
1027     * prevent the device from going to sleep.)
1028     *
1029     * There *are* some some touch events that really do count as user
1030     * activity, though.  For those, we need to manually poke the
1031     * PowerManager's userActivity method; see pokeUserActivity().
1032     */
1033    /* package */ void setIgnoreTouchUserActivity(boolean ignore) {
1034        if (VDBG) Log.d(LOG_TAG, "setIgnoreTouchUserActivity(" + ignore + ")...");
1035        mIgnoreTouchUserActivity = ignore;
1036        updatePokeLock();
1037    }
1038
1039    /**
1040     * Manually pokes the PowerManager's userActivity method.  Since we
1041     * hold the POKE_LOCK_IGNORE_TOUCH_AND_CHEEK_EVENTS poke lock while
1042     * the InCallScreen is active, we need to do this for touch events
1043     * that really do count as user activity (like DTMF key presses, or
1044     * unlocking the "touch lock" overlay.)
1045     */
1046    /* package */ void pokeUserActivity() {
1047        if (VDBG) Log.d(LOG_TAG, "pokeUserActivity()...");
1048        try {
1049            mPowerManagerService.userActivity(SystemClock.uptimeMillis(), false);
1050        } catch (RemoteException e) {
1051            Log.w(LOG_TAG, "mPowerManagerService.userActivity() failed: " + e);
1052        }
1053    }
1054
1055    /**
1056     * Set when a new outgoing call is beginning, so we can update
1057     * the proximity sensor state.
1058     * Cleared when the InCallScreen is no longer in the foreground,
1059     * in case the call fails without changing the telephony state.
1060     */
1061    /* package */ void setBeginningCall(boolean beginning) {
1062        // Note that we are beginning a new call, for proximity sensor support
1063        mBeginningCall = beginning;
1064        // Update the Proximity sensor based on mBeginningCall state
1065        updateProximitySensorMode(phone.getState());
1066    }
1067
1068    /**
1069     * Updates the wake lock used to control proximity sensor behavior,
1070     * based on the current state of the phone.  This method is called
1071     * from the CallNotifier on any phone state change.
1072     *
1073     * On devices that have a proximity sensor, to avoid false touches
1074     * during a call, we hold a PROXIMITY_SCREEN_OFF_WAKE_LOCK wake lock
1075     * whenever the phone is off hook.  (When held, that wake lock causes
1076     * the screen to turn off automatically when the sensor detects an
1077     * object close to the screen.)
1078     *
1079     * This method is a no-op for devices that don't have a proximity
1080     * sensor.
1081     *
1082     * Note this method doesn't care if the InCallScreen is the foreground
1083     * activity or not.  That's because we want the proximity sensor to be
1084     * enabled any time the phone is in use, to avoid false cheek events
1085     * for whatever app you happen to be running.
1086     *
1087     * Proximity wake lock will *not* be held if any one of the
1088     * conditions is true while on a call:
1089     * 1) If the audio is routed via Bluetooth
1090     * 2) If a wired headset is connected
1091     * 3) if the speaker is ON
1092     * 4) If the slider is open(i.e. the hardkeyboard is *not* hidden)
1093     *
1094     * @param state current state of the phone (see {@link Phone#State})
1095     */
1096    /* package */ void updateProximitySensorMode(Phone.State state) {
1097        if (VDBG) Log.d(LOG_TAG, "updateProximitySensorMode: state = " + state);
1098
1099        if (proximitySensorModeEnabled()) {
1100            synchronized (mProximityWakeLock) {
1101                // turn proximity sensor off and turn screen on immediately if
1102                // we are using a headset or the keyboard is open.
1103                boolean screenOnImmediately = (isHeadsetPlugged()
1104                            || PhoneUtils.isSpeakerOn(this)
1105                            || ((mBtHandsfree != null) && mBtHandsfree.isAudioOn())
1106                            || mIsHardKeyboardOpen);
1107
1108                if (((state == Phone.State.OFFHOOK) || mBeginningCall)&& !screenOnImmediately) {
1109                    // Phone is in use!  Arrange for the screen to turn off
1110                    // automatically when the sensor detects a close object.
1111                    if (!mProximityWakeLock.isHeld()) {
1112                        if (DBG) Log.d(LOG_TAG, "updateProximitySensorMode: acquiring...");
1113                        mProximityWakeLock.acquire();
1114                    } else {
1115                        if (VDBG) Log.d(LOG_TAG, "updateProximitySensorMode: lock already held.");
1116                    }
1117                } else {
1118                    // Phone is either idle, or ringing.  We don't want any
1119                    // special proximity sensor behavior in either case.
1120                    if (mProximityWakeLock.isHeld()) {
1121                        if (DBG) Log.d(LOG_TAG, "updateProximitySensorMode: releasing...");
1122                        // Wait until user has moved the phone away from his head if we are
1123                        // releasing due to the phone call ending.
1124                        // Qtherwise, turn screen on immediately
1125                        int flags =
1126                            (screenOnImmediately ? 0 : PowerManager.WAIT_FOR_PROXIMITY_NEGATIVE);
1127                        mProximityWakeLock.release(flags);
1128                    } else {
1129                        if (VDBG) {
1130                            Log.d(LOG_TAG, "updateProximitySensorMode: lock already released.");
1131                        }
1132                    }
1133                }
1134            }
1135        }
1136    }
1137
1138    /**
1139     * Notifies the phone app when the phone state changes.
1140     * Currently used only for proximity sensor support.
1141     */
1142    /* package */ void updatePhoneState(Phone.State state) {
1143        if (state != mLastPhoneState) {
1144            mLastPhoneState = state;
1145            updateProximitySensorMode(state);
1146            // clear our beginning call flag
1147            mBeginningCall = false;
1148            // While we are in call, the in-call screen should dismiss the keyguard.
1149            // This allows the user to press Home to go directly home without going through
1150            // an insecure lock screen.
1151            // But we do not want to do this if there is no active call so we do not
1152            // bypass the keyguard if the call is not answered or declined.
1153            if (mInCallScreen != null) {
1154                mInCallScreen.updateKeyguardPolicy(state == Phone.State.OFFHOOK);
1155            }
1156        }
1157    }
1158
1159    /* package */ Phone.State getPhoneState() {
1160        return mLastPhoneState;
1161    }
1162
1163    /**
1164     * @return true if this device supports the "proximity sensor
1165     * auto-lock" feature while in-call (see updateProximitySensorMode()).
1166     */
1167    /* package */ boolean proximitySensorModeEnabled() {
1168        return (mProximityWakeLock != null);
1169    }
1170
1171    KeyguardManager getKeyguardManager() {
1172        return mKeyguardManager;
1173    }
1174
1175    private void onMMIComplete(AsyncResult r) {
1176        if (VDBG) Log.d(LOG_TAG, "onMMIComplete()...");
1177        MmiCode mmiCode = (MmiCode) r.result;
1178        PhoneUtils.displayMMIComplete(phone, getInstance(), mmiCode, null, null);
1179    }
1180
1181    private void initForNewRadioTechnology() {
1182        if (DBG) Log.d(LOG_TAG, "initForNewRadioTechnology...");
1183
1184        if (phone.getPhoneType() == Phone.PHONE_TYPE_CDMA) {
1185            // Create an instance of CdmaPhoneCallState and initialize it to IDLE
1186            cdmaPhoneCallState = new CdmaPhoneCallState();
1187            cdmaPhoneCallState.CdmaPhoneCallStateInit();
1188
1189            //create instances of CDMA OTA data classes
1190            if (cdmaOtaProvisionData == null) {
1191                cdmaOtaProvisionData = new OtaUtils.CdmaOtaProvisionData();
1192            }
1193            if (cdmaOtaConfigData == null) {
1194                cdmaOtaConfigData = new OtaUtils.CdmaOtaConfigData();
1195            }
1196            if (cdmaOtaScreenState == null) {
1197                cdmaOtaScreenState = new OtaUtils.CdmaOtaScreenState();
1198            }
1199        }
1200
1201        ringer.updateRingerContextAfterRadioTechnologyChange(this.phone);
1202        notifier.updateCallNotifierRegistrationsAfterRadioTechnologyChange();
1203        if (mBtHandsfree != null) {
1204            mBtHandsfree.updateBtHandsfreeAfterRadioTechnologyChange();
1205        }
1206        if (mInCallScreen != null) {
1207            mInCallScreen.updateAfterRadioTechnologyChange();
1208        }
1209
1210        // Update registration for ICC status after radio technology change
1211        IccCard sim = phone.getIccCard();
1212        if (sim != null) {
1213            if (DBG) Log.d(LOG_TAG, "Update registration for ICC status...");
1214
1215            //Register all events new to the new active phone
1216            sim.registerForAbsent(mHandler, EVENT_SIM_ABSENT, null);
1217            sim.registerForLocked(mHandler, EVENT_SIM_LOCKED, null);
1218            sim.registerForNetworkLocked(mHandler, EVENT_SIM_NETWORK_LOCKED, null);
1219        }
1220    }
1221
1222
1223    /**
1224     * @return true if a wired headset is currently plugged in.
1225     *
1226     * @see Intent.ACTION_HEADSET_PLUG (which we listen for in mReceiver.onReceive())
1227     */
1228    boolean isHeadsetPlugged() {
1229        return mIsHeadsetPlugged;
1230    }
1231
1232    /**
1233     * @return true if the onscreen UI should currently be showing the
1234     * special "bluetooth is active" indication in a couple of places (in
1235     * which UI elements turn blue and/or show the bluetooth logo.)
1236     *
1237     * This depends on the BluetoothHeadset state *and* the current
1238     * telephony state; see shouldShowBluetoothIndication().
1239     *
1240     * @see CallCard
1241     * @see NotificationMgr.updateInCallNotification
1242     */
1243    /* package */ boolean showBluetoothIndication() {
1244        return mShowBluetoothIndication;
1245    }
1246
1247    /**
1248     * Recomputes the mShowBluetoothIndication flag based on the current
1249     * bluetooth state and current telephony state.
1250     *
1251     * This needs to be called any time the bluetooth headset state or the
1252     * telephony state changes.
1253     *
1254     * @param forceUiUpdate if true, force the UI elements that care
1255     *                      about this flag to update themselves.
1256     */
1257    /* package */ void updateBluetoothIndication(boolean forceUiUpdate) {
1258        mShowBluetoothIndication = shouldShowBluetoothIndication(mBluetoothHeadsetState,
1259                                                                 mBluetoothHeadsetAudioState,
1260                                                                 phone);
1261        if (forceUiUpdate) {
1262            // Post Handler messages to the various components that might
1263            // need to be refreshed based on the new state.
1264            if (isShowingCallScreen()) mInCallScreen.requestUpdateBluetoothIndication();
1265            mHandler.sendEmptyMessage(EVENT_UPDATE_INCALL_NOTIFICATION);
1266        }
1267
1268        // Update the Proximity sensor based on Bluetooth audio state
1269        updateProximitySensorMode(phone.getState());
1270    }
1271
1272    /**
1273     * UI policy helper function for the couple of places in the UI that
1274     * have some way of indicating that "bluetooth is in use."
1275     *
1276     * @return true if the onscreen UI should indicate that "bluetooth is in use",
1277     *         based on the specified bluetooth headset state, and the
1278     *         current state of the phone.
1279     * @see showBluetoothIndication()
1280     */
1281    private static boolean shouldShowBluetoothIndication(int bluetoothState,
1282                                                         int bluetoothAudioState,
1283                                                         Phone phone) {
1284        // We want the UI to indicate that "bluetooth is in use" in two
1285        // slightly different cases:
1286        //
1287        // (a) The obvious case: if a bluetooth headset is currently in
1288        //     use for an ongoing call.
1289        //
1290        // (b) The not-so-obvious case: if an incoming call is ringing,
1291        //     and we expect that audio *will* be routed to a bluetooth
1292        //     headset once the call is answered.
1293
1294        switch (phone.getState()) {
1295            case OFFHOOK:
1296                // This covers normal active calls, and also the case if
1297                // the foreground call is DIALING or ALERTING.  In this
1298                // case, bluetooth is considered "active" if a headset
1299                // is connected *and* audio is being routed to it.
1300                return ((bluetoothState == BluetoothHeadset.STATE_CONNECTED)
1301                        && (bluetoothAudioState == BluetoothHeadset.AUDIO_STATE_CONNECTED));
1302
1303            case RINGING:
1304                // If an incoming call is ringing, we're *not* yet routing
1305                // audio to the headset (since there's no in-call audio
1306                // yet!)  In this case, if a bluetooth headset is
1307                // connected at all, we assume that it'll become active
1308                // once the user answers the phone.
1309                return (bluetoothState == BluetoothHeadset.STATE_CONNECTED);
1310
1311            default:  // Presumably IDLE
1312                return false;
1313        }
1314    }
1315
1316
1317    /**
1318     * Receiver for misc intent broadcasts the Phone app cares about.
1319     */
1320    private class PhoneAppBroadcastReceiver extends BroadcastReceiver {
1321        @Override
1322        public void onReceive(Context context, Intent intent) {
1323            String action = intent.getAction();
1324            if (action.equals(Intent.ACTION_AIRPLANE_MODE_CHANGED)) {
1325                boolean enabled = System.getInt(getContentResolver(),
1326                        System.AIRPLANE_MODE_ON, 0) == 0;
1327                phone.setRadioPower(enabled);
1328            } else if (action.equals(BluetoothHeadset.ACTION_STATE_CHANGED)) {
1329                mBluetoothHeadsetState = intent.getIntExtra(BluetoothHeadset.EXTRA_STATE,
1330                                                            BluetoothHeadset.STATE_ERROR);
1331                if (VDBG) Log.d(LOG_TAG, "mReceiver: HEADSET_STATE_CHANGED_ACTION");
1332                if (VDBG) Log.d(LOG_TAG, "==> new state: " + mBluetoothHeadsetState);
1333                updateBluetoothIndication(true);  // Also update any visible UI if necessary
1334            } else if (action.equals(BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED)) {
1335                mBluetoothHeadsetAudioState =
1336                        intent.getIntExtra(BluetoothHeadset.EXTRA_AUDIO_STATE,
1337                                           BluetoothHeadset.STATE_ERROR);
1338                if (VDBG) Log.d(LOG_TAG, "mReceiver: HEADSET_AUDIO_STATE_CHANGED_ACTION");
1339                if (VDBG) Log.d(LOG_TAG, "==> new state: " + mBluetoothHeadsetAudioState);
1340                updateBluetoothIndication(true);  // Also update any visible UI if necessary
1341            } else if (action.equals(TelephonyIntents.ACTION_ANY_DATA_CONNECTION_STATE_CHANGED)) {
1342                if (VDBG) Log.d(LOG_TAG, "mReceiver: ACTION_ANY_DATA_CONNECTION_STATE_CHANGED");
1343                if (VDBG) Log.d(LOG_TAG, "- state: " + intent.getStringExtra(Phone.STATE_KEY));
1344                if (VDBG) Log.d(LOG_TAG, "- reason: "
1345                                + intent.getStringExtra(Phone.STATE_CHANGE_REASON_KEY));
1346
1347                // The "data disconnected due to roaming" notification is
1348                // visible if you've lost data connectivity because you're
1349                // roaming and you have the "data roaming" feature turned off.
1350                boolean disconnectedDueToRoaming = false;
1351                if ("DISCONNECTED".equals(intent.getStringExtra(Phone.STATE_KEY))) {
1352                    String reason = intent.getStringExtra(Phone.STATE_CHANGE_REASON_KEY);
1353                    if (Phone.REASON_ROAMING_ON.equals(reason)) {
1354                        // We just lost our data connection, and the reason
1355                        // is that we started roaming.  This implies that
1356                        // the user has data roaming turned off.
1357                        disconnectedDueToRoaming = true;
1358                    }
1359                }
1360                mHandler.sendEmptyMessage(disconnectedDueToRoaming
1361                                          ? EVENT_DATA_ROAMING_DISCONNECTED
1362                                          : EVENT_DATA_ROAMING_OK);
1363            } else if (action.equals(Intent.ACTION_HEADSET_PLUG)) {
1364                if (VDBG) Log.d(LOG_TAG, "mReceiver: ACTION_HEADSET_PLUG");
1365                if (VDBG) Log.d(LOG_TAG, "    state: " + intent.getIntExtra("state", 0));
1366                if (VDBG) Log.d(LOG_TAG, "    name: " + intent.getStringExtra("name"));
1367                mIsHeadsetPlugged = (intent.getIntExtra("state", 0) == 1);
1368                mHandler.sendMessage(mHandler.obtainMessage(EVENT_WIRED_HEADSET_PLUG, 0));
1369            } else if (action.equals(Intent.ACTION_BATTERY_LOW)) {
1370                if (VDBG) Log.d(LOG_TAG, "mReceiver: ACTION_BATTERY_LOW");
1371                notifier.sendBatteryLow();  // Play a warning tone if in-call
1372            } else if ((action.equals(TelephonyIntents.ACTION_SIM_STATE_CHANGED)) &&
1373                    (mPUKEntryActivity != null)) {
1374                // if an attempt to un-PUK-lock the device was made, while we're
1375                // receiving this state change notification, notify the handler.
1376                // NOTE: This is ONLY triggered if an attempt to un-PUK-lock has
1377                // been attempted.
1378                mHandler.sendMessage(mHandler.obtainMessage(EVENT_SIM_STATE_CHANGED,
1379                        intent.getStringExtra(IccCard.INTENT_KEY_ICC_STATE)));
1380            } else if (action.equals(TelephonyIntents.ACTION_RADIO_TECHNOLOGY_CHANGED)) {
1381                String newPhone = intent.getStringExtra(Phone.PHONE_NAME_KEY);
1382                Log.d(LOG_TAG, "Radio technology switched. Now " + newPhone + " is active.");
1383                initForNewRadioTechnology();
1384            } else if (action.equals(TelephonyIntents.ACTION_SERVICE_STATE_CHANGED)) {
1385                handleServiceStateChanged(intent);
1386            } else if (action.equals(TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED)) {
1387                if (phone.getPhoneType() == Phone.PHONE_TYPE_CDMA) {
1388                    Log.d(LOG_TAG, "Emergency Callback Mode arrived in PhoneApp.");
1389                    // Start Emergency Callback Mode service
1390                    if (intent.getBooleanExtra("phoneinECMState", false)) {
1391                        context.startService(new Intent(context,
1392                                EmergencyCallbackModeService.class));
1393                    }
1394                } else {
1395                    Log.e(LOG_TAG, "Error! Emergency Callback Mode not supported for " +
1396                            phone.getPhoneName() + " phones");
1397                }
1398            }
1399        }
1400    }
1401
1402    /**
1403     * Broadcast receiver for the ACTION_MEDIA_BUTTON broadcast intent.
1404     *
1405     * This functionality isn't lumped in with the other intents in
1406     * PhoneAppBroadcastReceiver because we instantiate this as a totally
1407     * separate BroadcastReceiver instance, since we need to manually
1408     * adjust its IntentFilter's priority (to make sure we get these
1409     * intents *before* the media player.)
1410     */
1411    private class MediaButtonBroadcastReceiver extends BroadcastReceiver {
1412        @Override
1413        public void onReceive(Context context, Intent intent) {
1414            KeyEvent event = (KeyEvent) intent.getParcelableExtra(Intent.EXTRA_KEY_EVENT);
1415            if (VDBG) Log.d(LOG_TAG,
1416                           "MediaButtonBroadcastReceiver.onReceive()...  event = " + event);
1417            if ((event != null)
1418                && (event.getKeyCode() == KeyEvent.KEYCODE_HEADSETHOOK)
1419                && (event.getAction() == KeyEvent.ACTION_DOWN)) {
1420
1421                if (event.getRepeatCount() == 0) {
1422                    // Mute ONLY on the initial keypress.
1423                    if (VDBG) Log.d(LOG_TAG, "MediaButtonBroadcastReceiver: HEADSETHOOK down!");
1424                    boolean consumed = PhoneUtils.handleHeadsetHook(phone);
1425                    if (VDBG) Log.d(LOG_TAG, "==> handleHeadsetHook(): consumed = " + consumed);
1426                    if (consumed) {
1427                        // If a headset is attached and the press is consumed, also update
1428                        // any UI items (such as an InCallScreen mute button) that may need to
1429                        // be updated if their state changed.
1430                        if (isShowingCallScreen()) {
1431                            updateInCallScreenTouchUi();
1432                        }
1433                        abortBroadcast();
1434                    }
1435                } else if (phone.getState() != Phone.State.IDLE) {
1436                    // As for any DOWN events other than the initial press, we consume
1437                    // (and ignore) those too if the phone is in use.  (Otherwise the
1438                    // music player will handle them, which would be confusing.)
1439                    abortBroadcast();
1440                }
1441            }
1442        }
1443    }
1444
1445    private void handleServiceStateChanged(Intent intent) {
1446        /**
1447         * This used to handle updating EriTextWidgetProvider this routine
1448         * and and listening for ACTION_SERVICE_STATE_CHANGED intents could
1449         * be removed. But leaving just in case it might be needed in the near
1450         * future.
1451         */
1452
1453        // If service just returned, start sending out the queued messages
1454        ServiceState ss = ServiceState.newFromBundle(intent.getExtras());
1455
1456        boolean hasService = true;
1457        boolean isCdma = false;
1458        String eriText = "";
1459
1460        if (ss != null) {
1461            int state = ss.getState();
1462            NotificationMgr.getDefault().updateNetworkSelection(state);
1463            switch (state) {
1464                case ServiceState.STATE_OUT_OF_SERVICE:
1465                case ServiceState.STATE_POWER_OFF:
1466                    hasService = false;
1467                    break;
1468            }
1469        } else {
1470            hasService = false;
1471        }
1472    }
1473
1474    public boolean isOtaCallInActiveState() {
1475        boolean otaCallActive = false;
1476        if (mInCallScreen != null) {
1477            otaCallActive = mInCallScreen.isOtaCallInActiveState();
1478        }
1479        if (VDBG) Log.d(LOG_TAG, "- isOtaCallInActiveState " + otaCallActive);
1480        return otaCallActive;
1481    }
1482
1483    public boolean isOtaCallInEndState() {
1484        boolean otaCallEnded = false;
1485        if (mInCallScreen != null) {
1486            otaCallEnded = mInCallScreen.isOtaCallInEndState();
1487        }
1488        if (VDBG) Log.d(LOG_TAG, "- isOtaCallInEndState " + otaCallEnded);
1489        return otaCallEnded;
1490    }
1491
1492    // it is safe to call clearOtaState() even if the InCallScreen isn't active
1493    public void clearOtaState() {
1494        if (DBG) Log.d(LOG_TAG, "- clearOtaState ...");
1495        if ((mInCallScreen != null)
1496                && (mInCallScreen.otaUtils != null)) {
1497            mInCallScreen.otaUtils.cleanOtaScreen(true);
1498            if (DBG) Log.d(LOG_TAG, "  - clearOtaState clears OTA screen");
1499        }
1500    }
1501
1502    // it is safe to call dismissOtaDialogs() even if the InCallScreen isn't active
1503    public void dismissOtaDialogs() {
1504        if (DBG) Log.d(LOG_TAG, "- dismissOtaDialogs ...");
1505        if ((mInCallScreen != null)
1506                && (mInCallScreen.otaUtils != null)) {
1507            mInCallScreen.otaUtils.dismissAllOtaDialogs();
1508            if (DBG) Log.d(LOG_TAG, "  - dismissOtaDialogs clears OTA dialogs");
1509        }
1510    }
1511
1512    // it is safe to call clearInCallScreenMode() even if the InCallScreen isn't active
1513    public void clearInCallScreenMode() {
1514        if (DBG) Log.d(LOG_TAG, "- clearInCallScreenMode ...");
1515        if (mInCallScreen != null) {
1516            mInCallScreen.resetInCallScreenMode();
1517        }
1518    }
1519
1520    // Update InCallScreen's touch UI. It is safe to call even if InCallScreen isn't active
1521    public void updateInCallScreenTouchUi() {
1522        if (DBG) Log.d(LOG_TAG, "- updateInCallScreenTouchUi ...");
1523        if (mInCallScreen != null) {
1524            mInCallScreen.requestUpdateTouchUi();
1525        }
1526    }
1527}
1528