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