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