Home | History | Annotate | Download | only in phone
      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 
     17 package com.android.phone;
     18 
     19 import android.app.Activity;
     20 import android.app.KeyguardManager;
     21 import android.app.ProgressDialog;
     22 import android.content.BroadcastReceiver;
     23 import android.content.ContentResolver;
     24 import android.content.Context;
     25 import android.content.ContextWrapper;
     26 import android.content.Intent;
     27 import android.content.IntentFilter;
     28 import android.media.AudioManager;
     29 import android.net.ConnectivityManager;
     30 import android.net.Uri;
     31 import android.os.AsyncResult;
     32 import android.os.Bundle;
     33 import android.os.Handler;
     34 import android.os.Message;
     35 import android.os.PersistableBundle;
     36 import android.os.PowerManager;
     37 import android.os.SystemClock;
     38 import android.os.SystemProperties;
     39 import android.os.UpdateLock;
     40 import android.os.UserManager;
     41 import android.preference.PreferenceManager;
     42 import android.provider.Settings;
     43 import android.telephony.CarrierConfigManager;
     44 import android.telephony.ServiceState;
     45 import android.telephony.SubscriptionManager;
     46 import android.util.Log;
     47 import android.widget.Toast;
     48 import com.android.internal.telephony.Call;
     49 import com.android.internal.telephony.CallManager;
     50 import com.android.internal.telephony.IccCardConstants;
     51 import com.android.internal.telephony.MmiCode;
     52 import com.android.internal.telephony.Phone;
     53 import com.android.internal.telephony.PhoneConstants;
     54 import com.android.internal.telephony.PhoneFactory;
     55 import com.android.internal.telephony.TelephonyCapabilities;
     56 import com.android.internal.telephony.TelephonyIntents;
     57 import com.android.phone.common.CallLogAsync;
     58 import com.android.phone.settings.SettingsConstants;
     59 import com.android.services.telephony.activation.SimActivationManager;
     60 import com.android.services.telephony.sip.SipUtil;
     61 
     62 /**
     63  * Global state for the telephony subsystem when running in the primary
     64  * phone process.
     65  */
     66 public class PhoneGlobals extends ContextWrapper {
     67     public static final String LOG_TAG = "PhoneApp";
     68 
     69     /**
     70      * Phone app-wide debug level:
     71      *   0 - no debug logging
     72      *   1 - normal debug logging if ro.debuggable is set (which is true in
     73      *       "eng" and "userdebug" builds but not "user" builds)
     74      *   2 - ultra-verbose debug logging
     75      *
     76      * Most individual classes in the phone app have a local DBG constant,
     77      * typically set to
     78      *   (PhoneApp.DBG_LEVEL >= 1) && (SystemProperties.getInt("ro.debuggable", 0) == 1)
     79      * or else
     80      *   (PhoneApp.DBG_LEVEL >= 2)
     81      * depending on the desired verbosity.
     82      *
     83      * ***** DO NOT SUBMIT WITH DBG_LEVEL > 0 *************
     84      */
     85     public static final int DBG_LEVEL = 0;
     86 
     87     private static final boolean DBG =
     88             (PhoneGlobals.DBG_LEVEL >= 1) && (SystemProperties.getInt("ro.debuggable", 0) == 1);
     89     private static final boolean VDBG = (PhoneGlobals.DBG_LEVEL >= 2);
     90 
     91     // Message codes; see mHandler below.
     92     private static final int EVENT_SIM_NETWORK_LOCKED = 3;
     93     private static final int EVENT_SIM_STATE_CHANGED = 8;
     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     private static final int EVENT_RESTART_SIP = 13;
     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     public static final int AIRPLANE_ON = 1;
    107     public static final int AIRPLANE_OFF = 0;
    108 
    109     /**
    110      * Allowable values for the wake lock code.
    111      *   SLEEP means the device can be put to sleep.
    112      *   PARTIAL means wake the processor, but we display can be kept off.
    113      *   FULL means wake both the processor and the display.
    114      */
    115     public enum WakeState {
    116         SLEEP,
    117         PARTIAL,
    118         FULL
    119     }
    120 
    121     private static PhoneGlobals sMe;
    122 
    123     // A few important fields we expose to the rest of the package
    124     // directly (rather than thru set/get methods) for efficiency.
    125     CallController callController;
    126     CallManager mCM;
    127     CallNotifier notifier;
    128     CallerInfoCache callerInfoCache;
    129     NotificationMgr notificationMgr;
    130     public PhoneInterfaceManager phoneMgr;
    131     public SimActivationManager simActivationManager;
    132     CarrierConfigLoader configLoader;
    133 
    134     private CallGatewayManager callGatewayManager;
    135     private Phone phoneInEcm;
    136 
    137     static boolean sVoiceCapable = true;
    138 
    139     // TODO: Remove, no longer used.
    140     CdmaPhoneCallState cdmaPhoneCallState;
    141 
    142     // The currently-active PUK entry activity and progress dialog.
    143     // Normally, these are the Emergency Dialer and the subsequent
    144     // progress dialog.  null if there is are no such objects in
    145     // the foreground.
    146     private Activity mPUKEntryActivity;
    147     private ProgressDialog mPUKEntryProgressDialog;
    148 
    149     private boolean mDataDisconnectedDueToRoaming = false;
    150 
    151     private WakeState mWakeState = WakeState.SLEEP;
    152 
    153     private PowerManager mPowerManager;
    154     private PowerManager.WakeLock mWakeLock;
    155     private PowerManager.WakeLock mPartialWakeLock;
    156     private KeyguardManager mKeyguardManager;
    157 
    158     private UpdateLock mUpdateLock;
    159 
    160     // Broadcast receiver for various intent broadcasts (see onCreate())
    161     private final BroadcastReceiver mReceiver = new PhoneAppBroadcastReceiver();
    162 
    163     /**
    164      * The singleton OtaUtils instance used for OTASP calls.
    165      *
    166      * The OtaUtils instance is created lazily the first time we need to
    167      * make an OTASP call, regardless of whether it's an interactive or
    168      * non-interactive OTASP call.
    169      */
    170     public OtaUtils otaUtils;
    171 
    172     // Following are the CDMA OTA information Objects used during OTA Call.
    173     // cdmaOtaProvisionData object store static OTA information that needs
    174     // to be maintained even during Slider open/close scenarios.
    175     // cdmaOtaConfigData object stores configuration info to control visiblity
    176     // of each OTA Screens.
    177     // cdmaOtaScreenState object store OTA Screen State information.
    178     public OtaUtils.CdmaOtaProvisionData cdmaOtaProvisionData;
    179     public OtaUtils.CdmaOtaConfigData cdmaOtaConfigData;
    180     public OtaUtils.CdmaOtaScreenState cdmaOtaScreenState;
    181     public OtaUtils.CdmaOtaInCallScreenUiState cdmaOtaInCallScreenUiState;
    182 
    183     Handler mHandler = new Handler() {
    184         @Override
    185         public void handleMessage(Message msg) {
    186             PhoneConstants.State phoneState;
    187             switch (msg.what) {
    188                 // TODO: This event should be handled by the lock screen, just
    189                 // like the "SIM missing" and "Sim locked" cases (bug 1804111).
    190                 case EVENT_SIM_NETWORK_LOCKED:
    191                     if (getCarrierConfig().getBoolean(
    192                             CarrierConfigManager.KEY_IGNORE_SIM_NETWORK_LOCKED_EVENTS_BOOL)) {
    193                         // Some products don't have the concept of a "SIM network lock"
    194                         Log.i(LOG_TAG, "Ignoring EVENT_SIM_NETWORK_LOCKED event; "
    195                               + "not showing 'SIM network unlock' PIN entry screen");
    196                     } else {
    197                         // Normal case: show the "SIM network unlock" PIN entry screen.
    198                         // The user won't be able to do anything else until
    199                         // they enter a valid SIM network PIN.
    200                         Log.i(LOG_TAG, "show sim depersonal panel");
    201                         IccNetworkDepersonalizationPanel.showDialog();
    202                     }
    203                     break;
    204 
    205                 case EVENT_DATA_ROAMING_DISCONNECTED:
    206                     notificationMgr.showDataDisconnectedRoaming();
    207                     break;
    208 
    209                 case EVENT_DATA_ROAMING_OK:
    210                     notificationMgr.hideDataDisconnectedRoaming();
    211                     break;
    212 
    213                 case MMI_COMPLETE:
    214                     onMMIComplete((AsyncResult) msg.obj);
    215                     break;
    216 
    217                 case MMI_CANCEL:
    218                     PhoneUtils.cancelMmiCode(mCM.getFgPhone());
    219                     break;
    220 
    221                 case EVENT_SIM_STATE_CHANGED:
    222                     // Marks the event where the SIM goes into ready state.
    223                     // Right now, this is only used for the PUK-unlocking
    224                     // process.
    225                     if (msg.obj.equals(IccCardConstants.INTENT_VALUE_ICC_READY)) {
    226                         // when the right event is triggered and there
    227                         // are UI objects in the foreground, we close
    228                         // them to display the lock panel.
    229                         if (mPUKEntryActivity != null) {
    230                             mPUKEntryActivity.finish();
    231                             mPUKEntryActivity = null;
    232                         }
    233                         if (mPUKEntryProgressDialog != null) {
    234                             mPUKEntryProgressDialog.dismiss();
    235                             mPUKEntryProgressDialog = null;
    236                         }
    237                     }
    238                     break;
    239 
    240                 case EVENT_UNSOL_CDMA_INFO_RECORD:
    241                     //TODO: handle message here;
    242                     break;
    243                 case EVENT_RESTART_SIP:
    244                     // This should only run if the Phone process crashed and was restarted. We do
    245                     // not want this running if the device is still in the FBE encrypted state.
    246                     // This is the same procedure that is triggered in the SipBroadcastReceiver
    247                     // upon BOOT_COMPLETED.
    248                     UserManager userManager = UserManager.get(sMe);
    249                     if (userManager != null && userManager.isUserUnlocked()) {
    250                         SipUtil.startSipService();
    251                     }
    252                     break;
    253             }
    254         }
    255     };
    256 
    257     public PhoneGlobals(Context context) {
    258         super(context);
    259         sMe = this;
    260     }
    261 
    262     public void onCreate() {
    263         if (VDBG) Log.v(LOG_TAG, "onCreate()...");
    264 
    265         ContentResolver resolver = getContentResolver();
    266 
    267         // Cache the "voice capable" flag.
    268         // This flag currently comes from a resource (which is
    269         // overrideable on a per-product basis):
    270         sVoiceCapable =
    271                 getResources().getBoolean(com.android.internal.R.bool.config_voice_capable);
    272         // ...but this might eventually become a PackageManager "system
    273         // feature" instead, in which case we'd do something like:
    274         // sVoiceCapable =
    275         //   getPackageManager().hasSystemFeature(PackageManager.FEATURE_TELEPHONY_VOICE_CALLS);
    276 
    277         if (mCM == null) {
    278             // Initialize the telephony framework
    279             PhoneFactory.makeDefaultPhones(this);
    280 
    281             // Start TelephonyDebugService After the default phone is created.
    282             Intent intent = new Intent(this, TelephonyDebugService.class);
    283             startService(intent);
    284 
    285             mCM = CallManager.getInstance();
    286             for (Phone phone : PhoneFactory.getPhones()) {
    287                 mCM.registerPhone(phone);
    288             }
    289 
    290             // Create the NotificationMgr singleton, which is used to display
    291             // status bar icons and control other status bar behavior.
    292             notificationMgr = NotificationMgr.init(this);
    293 
    294             // If PhoneGlobals has crashed and is being restarted, then restart.
    295             mHandler.sendEmptyMessage(EVENT_RESTART_SIP);
    296 
    297             // Create an instance of CdmaPhoneCallState and initialize it to IDLE
    298             cdmaPhoneCallState = new CdmaPhoneCallState();
    299             cdmaPhoneCallState.CdmaPhoneCallStateInit();
    300 
    301             // before registering for phone state changes
    302             mPowerManager = (PowerManager) getSystemService(Context.POWER_SERVICE);
    303             mWakeLock = mPowerManager.newWakeLock(PowerManager.FULL_WAKE_LOCK, LOG_TAG);
    304             // lock used to keep the processor awake, when we don't care for the display.
    305             mPartialWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK
    306                     | PowerManager.ON_AFTER_RELEASE, LOG_TAG);
    307 
    308             mKeyguardManager = (KeyguardManager) getSystemService(Context.KEYGUARD_SERVICE);
    309 
    310             // Get UpdateLock to suppress system-update related events (e.g. dialog show-up)
    311             // during phone calls.
    312             mUpdateLock = new UpdateLock("phone");
    313 
    314             if (DBG) Log.d(LOG_TAG, "onCreate: mUpdateLock: " + mUpdateLock);
    315 
    316             CallLogger callLogger = new CallLogger(this, new CallLogAsync());
    317 
    318             callGatewayManager = CallGatewayManager.getInstance();
    319 
    320             // Create the CallController singleton, which is the interface
    321             // to the telephony layer for user-initiated telephony functionality
    322             // (like making outgoing calls.)
    323             callController = CallController.init(this, callLogger, callGatewayManager);
    324 
    325             // Create the CallerInfoCache singleton, which remembers custom ring tone and
    326             // send-to-voicemail settings.
    327             //
    328             // The asynchronous caching will start just after this call.
    329             callerInfoCache = CallerInfoCache.init(this);
    330 
    331             phoneMgr = PhoneInterfaceManager.init(this, PhoneFactory.getDefaultPhone());
    332 
    333             configLoader = CarrierConfigLoader.init(this);
    334 
    335             // Create the CallNotifer singleton, which handles
    336             // asynchronous events from the telephony layer (like
    337             // launching the incoming-call UI when an incoming call comes
    338             // in.)
    339             notifier = CallNotifier.init(this);
    340 
    341             PhoneUtils.registerIccStatus(mHandler, EVENT_SIM_NETWORK_LOCKED);
    342 
    343             // register for MMI/USSD
    344             mCM.registerForMmiComplete(mHandler, MMI_COMPLETE, null);
    345 
    346             // register connection tracking to PhoneUtils
    347             PhoneUtils.initializeConnectionHandler(mCM);
    348 
    349             // Register for misc other intent broadcasts.
    350             IntentFilter intentFilter =
    351                     new IntentFilter(Intent.ACTION_AIRPLANE_MODE_CHANGED);
    352             intentFilter.addAction(TelephonyIntents.ACTION_ANY_DATA_CONNECTION_STATE_CHANGED);
    353             intentFilter.addAction(TelephonyIntents.ACTION_SIM_STATE_CHANGED);
    354             intentFilter.addAction(TelephonyIntents.ACTION_RADIO_TECHNOLOGY_CHANGED);
    355             intentFilter.addAction(TelephonyIntents.ACTION_SERVICE_STATE_CHANGED);
    356             intentFilter.addAction(TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED);
    357             registerReceiver(mReceiver, intentFilter);
    358 
    359             //set the default values for the preferences in the phone.
    360             PreferenceManager.setDefaultValues(this, R.xml.network_setting, false);
    361 
    362             PreferenceManager.setDefaultValues(this, R.xml.call_feature_setting, false);
    363 
    364             // Make sure the audio mode (along with some
    365             // audio-mode-related state of our own) is initialized
    366             // correctly, given the current state of the phone.
    367             PhoneUtils.setAudioMode(mCM);
    368         }
    369 
    370         cdmaOtaProvisionData = new OtaUtils.CdmaOtaProvisionData();
    371         cdmaOtaConfigData = new OtaUtils.CdmaOtaConfigData();
    372         cdmaOtaScreenState = new OtaUtils.CdmaOtaScreenState();
    373         cdmaOtaInCallScreenUiState = new OtaUtils.CdmaOtaInCallScreenUiState();
    374 
    375         simActivationManager = new SimActivationManager();
    376 
    377         // XXX pre-load the SimProvider so that it's ready
    378         resolver.getType(Uri.parse("content://icc/adn"));
    379 
    380         // TODO: Register for Cdma Information Records
    381         // phone.registerCdmaInformationRecord(mHandler, EVENT_UNSOL_CDMA_INFO_RECORD, null);
    382 
    383         // Read HAC settings and configure audio hardware
    384         if (getResources().getBoolean(R.bool.hac_enabled)) {
    385             int hac = android.provider.Settings.System.getInt(
    386                     getContentResolver(),
    387                     android.provider.Settings.System.HEARING_AID,
    388                     0);
    389             AudioManager audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
    390             audioManager.setParameter(SettingsConstants.HAC_KEY,
    391                     hac == SettingsConstants.HAC_ENABLED
    392                             ? SettingsConstants.HAC_VAL_ON : SettingsConstants.HAC_VAL_OFF);
    393         }
    394     }
    395 
    396     /**
    397      * Returns the singleton instance of the PhoneApp.
    398      */
    399     public static PhoneGlobals getInstance() {
    400         if (sMe == null) {
    401             throw new IllegalStateException("No PhoneGlobals here!");
    402         }
    403         return sMe;
    404     }
    405 
    406     /**
    407      * Returns the singleton instance of the PhoneApp if running as the
    408      * primary user, otherwise null.
    409      */
    410     static PhoneGlobals getInstanceIfPrimary() {
    411         return sMe;
    412     }
    413 
    414     /**
    415      * Returns the default phone.
    416      *
    417      * WARNING: This method should be used carefully, now that there may be multiple phones.
    418      */
    419     public static Phone getPhone() {
    420         return PhoneFactory.getDefaultPhone();
    421     }
    422 
    423     public static Phone getPhone(int subId) {
    424         return PhoneFactory.getPhone(SubscriptionManager.getPhoneId(subId));
    425     }
    426 
    427     /* package */ CallManager getCallManager() {
    428         return mCM;
    429     }
    430 
    431     public PersistableBundle getCarrierConfig() {
    432         return getCarrierConfigForSubId(SubscriptionManager.getDefaultSubscriptionId());
    433     }
    434 
    435     public PersistableBundle getCarrierConfigForSubId(int subId) {
    436         return configLoader.getConfigForSubId(subId);
    437     }
    438 
    439     /**
    440      * Handles OTASP-related events from the telephony layer.
    441      *
    442      * While an OTASP call is active, the CallNotifier forwards
    443      * OTASP-related telephony events to this method.
    444      */
    445     void handleOtaspEvent(Message msg) {
    446         if (DBG) Log.d(LOG_TAG, "handleOtaspEvent(message " + msg + ")...");
    447 
    448         if (otaUtils == null) {
    449             // We shouldn't be getting OTASP events without ever
    450             // having started the OTASP call in the first place!
    451             Log.w(LOG_TAG, "handleOtaEvents: got an event but otaUtils is null! "
    452                   + "message = " + msg);
    453             return;
    454         }
    455 
    456         otaUtils.onOtaProvisionStatusChanged((AsyncResult) msg.obj);
    457     }
    458 
    459     /**
    460      * Similarly, handle the disconnect event of an OTASP call
    461      * by forwarding it to the OtaUtils instance.
    462      */
    463     /* package */ void handleOtaspDisconnect() {
    464         if (DBG) Log.d(LOG_TAG, "handleOtaspDisconnect()...");
    465 
    466         if (otaUtils == null) {
    467             // We shouldn't be getting OTASP events without ever
    468             // having started the OTASP call in the first place!
    469             Log.w(LOG_TAG, "handleOtaspDisconnect: otaUtils is null!");
    470             return;
    471         }
    472 
    473         otaUtils.onOtaspDisconnect();
    474     }
    475 
    476     /**
    477      * Sets the activity responsible for un-PUK-blocking the device
    478      * so that we may close it when we receive a positive result.
    479      * mPUKEntryActivity is also used to indicate to the device that
    480      * we are trying to un-PUK-lock the phone. In other words, iff
    481      * it is NOT null, then we are trying to unlock and waiting for
    482      * the SIM to move to READY state.
    483      *
    484      * @param activity is the activity to close when PUK has
    485      * finished unlocking. Can be set to null to indicate the unlock
    486      * or SIM READYing process is over.
    487      */
    488     void setPukEntryActivity(Activity activity) {
    489         mPUKEntryActivity = activity;
    490     }
    491 
    492     Activity getPUKEntryActivity() {
    493         return mPUKEntryActivity;
    494     }
    495 
    496     /**
    497      * Sets the dialog responsible for notifying the user of un-PUK-
    498      * blocking - SIM READYing progress, so that we may dismiss it
    499      * when we receive a positive result.
    500      *
    501      * @param dialog indicates the progress dialog informing the user
    502      * of the state of the device.  Dismissed upon completion of
    503      * READYing process
    504      */
    505     void setPukEntryProgressDialog(ProgressDialog dialog) {
    506         mPUKEntryProgressDialog = dialog;
    507     }
    508 
    509     /**
    510      * Controls whether or not the screen is allowed to sleep.
    511      *
    512      * Once sleep is allowed (WakeState is SLEEP), it will rely on the
    513      * settings for the poke lock to determine when to timeout and let
    514      * the device sleep {@link PhoneGlobals#setScreenTimeout}.
    515      *
    516      * @param ws tells the device to how to wake.
    517      */
    518     /* package */ void requestWakeState(WakeState ws) {
    519         if (VDBG) Log.d(LOG_TAG, "requestWakeState(" + ws + ")...");
    520         synchronized (this) {
    521             if (mWakeState != ws) {
    522                 switch (ws) {
    523                     case PARTIAL:
    524                         // acquire the processor wake lock, and release the FULL
    525                         // lock if it is being held.
    526                         mPartialWakeLock.acquire();
    527                         if (mWakeLock.isHeld()) {
    528                             mWakeLock.release();
    529                         }
    530                         break;
    531                     case FULL:
    532                         // acquire the full wake lock, and release the PARTIAL
    533                         // lock if it is being held.
    534                         mWakeLock.acquire();
    535                         if (mPartialWakeLock.isHeld()) {
    536                             mPartialWakeLock.release();
    537                         }
    538                         break;
    539                     case SLEEP:
    540                     default:
    541                         // release both the PARTIAL and FULL locks.
    542                         if (mWakeLock.isHeld()) {
    543                             mWakeLock.release();
    544                         }
    545                         if (mPartialWakeLock.isHeld()) {
    546                             mPartialWakeLock.release();
    547                         }
    548                         break;
    549                 }
    550                 mWakeState = ws;
    551             }
    552         }
    553     }
    554 
    555     /**
    556      * If we are not currently keeping the screen on, then poke the power
    557      * manager to wake up the screen for the user activity timeout duration.
    558      */
    559     /* package */ void wakeUpScreen() {
    560         synchronized (this) {
    561             if (mWakeState == WakeState.SLEEP) {
    562                 if (DBG) Log.d(LOG_TAG, "pulse screen lock");
    563                 mPowerManager.wakeUp(SystemClock.uptimeMillis(), "android.phone:WAKE");
    564             }
    565         }
    566     }
    567 
    568     /**
    569      * Sets the wake state and screen timeout based on the current state
    570      * of the phone, and the current state of the in-call UI.
    571      *
    572      * This method is a "UI Policy" wrapper around
    573      * {@link PhoneGlobals#requestWakeState} and {@link PhoneGlobals#setScreenTimeout}.
    574      *
    575      * It's safe to call this method regardless of the state of the Phone
    576      * (e.g. whether or not it's idle), and regardless of the state of the
    577      * Phone UI (e.g. whether or not the InCallScreen is active.)
    578      */
    579     /* package */ void updateWakeState() {
    580         PhoneConstants.State state = mCM.getState();
    581 
    582         // True if the speakerphone is in use.  (If so, we *always* use
    583         // the default timeout.  Since the user is obviously not holding
    584         // the phone up to his/her face, we don't need to worry about
    585         // false touches, and thus don't need to turn the screen off so
    586         // aggressively.)
    587         // Note that we need to make a fresh call to this method any
    588         // time the speaker state changes.  (That happens in
    589         // PhoneUtils.turnOnSpeaker().)
    590         boolean isSpeakerInUse = (state == PhoneConstants.State.OFFHOOK) && PhoneUtils.isSpeakerOn(this);
    591 
    592         // TODO (bug 1440854): The screen timeout *might* also need to
    593         // depend on the bluetooth state, but this isn't as clear-cut as
    594         // the speaker state (since while using BT it's common for the
    595         // user to put the phone straight into a pocket, in which case the
    596         // timeout should probably still be short.)
    597 
    598         // Decide whether to force the screen on or not.
    599         //
    600         // Force the screen to be on if the phone is ringing or dialing,
    601         // or if we're displaying the "Call ended" UI for a connection in
    602         // the "disconnected" state.
    603         // However, if the phone is disconnected while the user is in the
    604         // middle of selecting a quick response message, we should not force
    605         // the screen to be on.
    606         //
    607         boolean isRinging = (state == PhoneConstants.State.RINGING);
    608         boolean isDialing = (mCM.getFgPhone().getForegroundCall().getState() == Call.State.DIALING);
    609         boolean keepScreenOn = isRinging || isDialing;
    610         // keepScreenOn == true means we'll hold a full wake lock:
    611         requestWakeState(keepScreenOn ? WakeState.FULL : WakeState.SLEEP);
    612     }
    613 
    614     KeyguardManager getKeyguardManager() {
    615         return mKeyguardManager;
    616     }
    617 
    618     private void onMMIComplete(AsyncResult r) {
    619         if (VDBG) Log.d(LOG_TAG, "onMMIComplete()...");
    620         MmiCode mmiCode = (MmiCode) r.result;
    621         PhoneUtils.displayMMIComplete(mmiCode.getPhone(), getInstance(), mmiCode, null, null);
    622     }
    623 
    624     private void initForNewRadioTechnology(int phoneId) {
    625         if (DBG) Log.d(LOG_TAG, "initForNewRadioTechnology...");
    626 
    627         final Phone phone = PhoneFactory.getPhone(phoneId);
    628         if (phone == null || !TelephonyCapabilities.supportsOtasp(phone)) {
    629             // Clean up OTA for non-CDMA since it is only valid for CDMA.
    630             clearOtaState();
    631         }
    632 
    633         notifier.updateCallNotifierRegistrationsAfterRadioTechnologyChange();
    634     }
    635 
    636     private void handleAirplaneModeChange(Context context, int newMode) {
    637         int cellState = Settings.Global.getInt(context.getContentResolver(),
    638                 Settings.Global.CELL_ON, PhoneConstants.CELL_ON_FLAG);
    639         boolean isAirplaneNewlyOn = (newMode == 1);
    640         switch (cellState) {
    641             case PhoneConstants.CELL_OFF_FLAG:
    642                 // Airplane mode does not affect the cell radio if user
    643                 // has turned it off.
    644                 break;
    645             case PhoneConstants.CELL_ON_FLAG:
    646                 maybeTurnCellOff(context, isAirplaneNewlyOn);
    647                 break;
    648             case PhoneConstants.CELL_OFF_DUE_TO_AIRPLANE_MODE_FLAG:
    649                 maybeTurnCellOn(context, isAirplaneNewlyOn);
    650                 break;
    651         }
    652     }
    653 
    654     /*
    655      * Returns true if the radio must be turned off when entering airplane mode.
    656      */
    657     private boolean isCellOffInAirplaneMode(Context context) {
    658         String airplaneModeRadios = Settings.Global.getString(context.getContentResolver(),
    659                 Settings.Global.AIRPLANE_MODE_RADIOS);
    660         return airplaneModeRadios == null
    661                 || airplaneModeRadios.contains(Settings.Global.RADIO_CELL);
    662     }
    663 
    664     private void setRadioPowerOff(Context context) {
    665         Log.i(LOG_TAG, "Turning radio off - airplane");
    666         Settings.Global.putInt(context.getContentResolver(), Settings.Global.CELL_ON,
    667                  PhoneConstants.CELL_OFF_DUE_TO_AIRPLANE_MODE_FLAG);
    668         Settings.Global.putInt(getContentResolver(), Settings.Global.ENABLE_CELLULAR_ON_BOOT, 0);
    669         PhoneUtils.setRadioPower(false);
    670     }
    671 
    672     private void setRadioPowerOn(Context context) {
    673         Log.i(LOG_TAG, "Turning radio on - airplane");
    674         Settings.Global.putInt(context.getContentResolver(), Settings.Global.CELL_ON,
    675                 PhoneConstants.CELL_ON_FLAG);
    676         Settings.Global.putInt(getContentResolver(), Settings.Global.ENABLE_CELLULAR_ON_BOOT,
    677                 1);
    678         PhoneUtils.setRadioPower(true);
    679     }
    680 
    681     private void maybeTurnCellOff(Context context, boolean isAirplaneNewlyOn) {
    682         if (isAirplaneNewlyOn) {
    683             // If we are trying to turn off the radio, make sure there are no active
    684             // emergency calls.  If there are, switch airplane mode back to off.
    685             if (PhoneUtils.isInEmergencyCall(mCM)) {
    686                 // Switch airplane mode back to off.
    687                 ConnectivityManager.from(this).setAirplaneMode(false);
    688                 Toast.makeText(this, R.string.radio_off_during_emergency_call, Toast.LENGTH_LONG)
    689                         .show();
    690                 Log.i(LOG_TAG, "Ignoring airplane mode: emergency call. Turning airplane off");
    691             } else if (isCellOffInAirplaneMode(context)) {
    692                 setRadioPowerOff(context);
    693             } else {
    694                 Log.i(LOG_TAG, "Ignoring airplane mode: settings prevent cell radio power off");
    695             }
    696         }
    697     }
    698 
    699     private void maybeTurnCellOn(Context context, boolean isAirplaneNewlyOn) {
    700         if (!isAirplaneNewlyOn) {
    701             setRadioPowerOn(context);
    702         }
    703     }
    704 
    705     /**
    706      * Receiver for misc intent broadcasts the Phone app cares about.
    707      */
    708     private class PhoneAppBroadcastReceiver extends BroadcastReceiver {
    709         @Override
    710         public void onReceive(Context context, Intent intent) {
    711             String action = intent.getAction();
    712             if (action.equals(Intent.ACTION_AIRPLANE_MODE_CHANGED)) {
    713                 int airplaneMode = Settings.Global.getInt(getContentResolver(),
    714                         Settings.Global.AIRPLANE_MODE_ON, AIRPLANE_OFF);
    715                 // Treat any non-OFF values as ON.
    716                 if (airplaneMode != AIRPLANE_OFF) {
    717                     airplaneMode = AIRPLANE_ON;
    718                 }
    719                 handleAirplaneModeChange(context, airplaneMode);
    720             } else if (action.equals(TelephonyIntents.ACTION_ANY_DATA_CONNECTION_STATE_CHANGED)) {
    721                 int subId = intent.getIntExtra(PhoneConstants.SUBSCRIPTION_KEY,
    722                         SubscriptionManager.INVALID_SUBSCRIPTION_ID);
    723                 int phoneId = SubscriptionManager.getPhoneId(subId);
    724                 String state = intent.getStringExtra(PhoneConstants.STATE_KEY);
    725                 if (VDBG) {
    726                     Log.d(LOG_TAG, "mReceiver: ACTION_ANY_DATA_CONNECTION_STATE_CHANGED");
    727                     Log.d(LOG_TAG, "- state: " + state);
    728                     Log.d(LOG_TAG, "- reason: "
    729                     + intent.getStringExtra(PhoneConstants.STATE_CHANGE_REASON_KEY));
    730                     Log.d(LOG_TAG, "- subId: " + subId);
    731                     Log.d(LOG_TAG, "- phoneId: " + phoneId);
    732                 }
    733                 Phone phone = SubscriptionManager.isValidPhoneId(phoneId) ?
    734                         PhoneFactory.getPhone(phoneId) : PhoneFactory.getDefaultPhone();
    735 
    736                 // The "data disconnected due to roaming" notification is shown
    737                 // if (a) you have the "data roaming" feature turned off, and
    738                 // (b) you just lost data connectivity because you're roaming.
    739                 boolean disconnectedDueToRoaming =
    740                         !phone.getDataRoamingEnabled()
    741                         && PhoneConstants.DataState.DISCONNECTED.equals(state)
    742                         && Phone.REASON_ROAMING_ON.equals(
    743                             intent.getStringExtra(PhoneConstants.STATE_CHANGE_REASON_KEY));
    744                 if (mDataDisconnectedDueToRoaming != disconnectedDueToRoaming) {
    745                     mDataDisconnectedDueToRoaming = disconnectedDueToRoaming;
    746                     mHandler.sendEmptyMessage(disconnectedDueToRoaming
    747                             ? EVENT_DATA_ROAMING_DISCONNECTED : EVENT_DATA_ROAMING_OK);
    748                 }
    749             } else if ((action.equals(TelephonyIntents.ACTION_SIM_STATE_CHANGED)) &&
    750                     (mPUKEntryActivity != null)) {
    751                 // if an attempt to un-PUK-lock the device was made, while we're
    752                 // receiving this state change notification, notify the handler.
    753                 // NOTE: This is ONLY triggered if an attempt to un-PUK-lock has
    754                 // been attempted.
    755                 mHandler.sendMessage(mHandler.obtainMessage(EVENT_SIM_STATE_CHANGED,
    756                         intent.getStringExtra(IccCardConstants.INTENT_KEY_ICC_STATE)));
    757             } else if (action.equals(TelephonyIntents.ACTION_RADIO_TECHNOLOGY_CHANGED)) {
    758                 String newPhone = intent.getStringExtra(PhoneConstants.PHONE_NAME_KEY);
    759                 int phoneId = intent.getIntExtra(PhoneConstants.PHONE_KEY,
    760                         SubscriptionManager.INVALID_PHONE_INDEX);
    761                 Log.d(LOG_TAG, "Radio technology switched. Now " + newPhone + " (" + phoneId
    762                         + ") is active.");
    763                 initForNewRadioTechnology(phoneId);
    764             } else if (action.equals(TelephonyIntents.ACTION_SERVICE_STATE_CHANGED)) {
    765                 handleServiceStateChanged(intent);
    766             } else if (action.equals(TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED)) {
    767                 int phoneId = intent.getIntExtra(PhoneConstants.PHONE_KEY, 0);
    768                 phoneInEcm = getPhone(phoneId);
    769                 Log.d(LOG_TAG, "Emergency Callback Mode. phoneId:" + phoneId);
    770                 if (phoneInEcm != null) {
    771                     if (TelephonyCapabilities.supportsEcm(phoneInEcm)) {
    772                         Log.d(LOG_TAG, "Emergency Callback Mode arrived in PhoneApp.");
    773                         // Start Emergency Callback Mode service
    774                         if (intent.getBooleanExtra("phoneinECMState", false)) {
    775                             context.startService(new Intent(context,
    776                                     EmergencyCallbackModeService.class));
    777                         } else {
    778                             phoneInEcm = null;
    779                         }
    780                     } else {
    781                         // It doesn't make sense to get ACTION_EMERGENCY_CALLBACK_MODE_CHANGED
    782                         // on a device that doesn't support ECM in the first place.
    783                         Log.e(LOG_TAG, "Got ACTION_EMERGENCY_CALLBACK_MODE_CHANGED, but "
    784                                 + "ECM isn't supported for phone: " + phoneInEcm.getPhoneName());
    785                         phoneInEcm = null;
    786                     }
    787                 } else {
    788                     Log.w(LOG_TAG, "phoneInEcm is null.");
    789                 }
    790             }
    791         }
    792     }
    793 
    794     private void handleServiceStateChanged(Intent intent) {
    795         /**
    796          * This used to handle updating EriTextWidgetProvider this routine
    797          * and and listening for ACTION_SERVICE_STATE_CHANGED intents could
    798          * be removed. But leaving just in case it might be needed in the near
    799          * future.
    800          */
    801 
    802         // If service just returned, start sending out the queued messages
    803         Bundle extras = intent.getExtras();
    804         if (extras != null) {
    805             ServiceState ss = ServiceState.newFromBundle(extras);
    806             if (ss != null) {
    807                 int state = ss.getState();
    808                 notificationMgr.updateNetworkSelection(state);
    809             }
    810         }
    811     }
    812 
    813     // it is safe to call clearOtaState() even if the InCallScreen isn't active
    814     public void clearOtaState() {
    815         if (DBG) Log.d(LOG_TAG, "- clearOtaState ...");
    816         if (otaUtils != null) {
    817             otaUtils.cleanOtaScreen(true);
    818             if (DBG) Log.d(LOG_TAG, "  - clearOtaState clears OTA screen");
    819         }
    820     }
    821 
    822     // it is safe to call dismissOtaDialogs() even if the InCallScreen isn't active
    823     public void dismissOtaDialogs() {
    824         if (DBG) Log.d(LOG_TAG, "- dismissOtaDialogs ...");
    825         if (otaUtils != null) {
    826             otaUtils.dismissAllOtaDialogs();
    827             if (DBG) Log.d(LOG_TAG, "  - dismissOtaDialogs clears OTA dialogs");
    828         }
    829     }
    830 
    831     public Phone getPhoneInEcm() {
    832         return phoneInEcm;
    833     }
    834 
    835     /**
    836      * Triggers a refresh of the message waiting (voicemail) indicator.
    837      *
    838      * @param subId the subscription id we should refresh the notification for.
    839      */
    840     public void refreshMwiIndicator(int subId) {
    841         notificationMgr.refreshMwi(subId);
    842     }
    843 
    844     /**
    845      * Dismisses the message waiting (voicemail) indicator.
    846      *
    847      * @param subId the subscription id we should dismiss the notification for.
    848      */
    849     public void clearMwiIndicator(int subId) {
    850         // Setting voiceMessageCount to 0 will remove the current notification and clear the system
    851         // cached value.
    852         Phone phone = getPhone(subId);
    853         if (phone == null) {
    854             Log.w(LOG_TAG, "clearMwiIndicator on null phone, subId:" + subId);
    855         } else {
    856             phone.setVoiceMessageCount(0);
    857         }
    858     }
    859 }
    860