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