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.net.sip.SipManager;
     32 import android.os.AsyncResult;
     33 import android.os.Bundle;
     34 import android.os.Handler;
     35 import android.os.Message;
     36 import android.os.PersistableBundle;
     37 import android.os.PowerManager;
     38 import android.os.SystemClock;
     39 import android.os.SystemProperties;
     40 import android.os.UpdateLock;
     41 import android.os.UserManager;
     42 import android.preference.PreferenceManager;
     43 import android.provider.Settings;
     44 import android.telephony.CarrierConfigManager;
     45 import android.telephony.ServiceState;
     46 import android.telephony.SubscriptionManager;
     47 import android.telephony.TelephonyManager;
     48 import android.util.LocalLog;
     49 import android.util.Log;
     50 import android.widget.Toast;
     51 
     52 import com.android.internal.telephony.Call;
     53 import com.android.internal.telephony.CallManager;
     54 import com.android.internal.telephony.IccCardConstants;
     55 import com.android.internal.telephony.MmiCode;
     56 import com.android.internal.telephony.Phone;
     57 import com.android.internal.telephony.PhoneConstants;
     58 import com.android.internal.telephony.PhoneFactory;
     59 import com.android.internal.telephony.SettingsObserver;
     60 import com.android.internal.telephony.TelephonyCapabilities;
     61 import com.android.internal.telephony.TelephonyIntents;
     62 import com.android.internal.telephony.dataconnection.DataConnectionReasons;
     63 import com.android.internal.telephony.dataconnection.DataConnectionReasons.DataDisallowedReasonType;
     64 import com.android.internal.util.IndentingPrintWriter;
     65 import com.android.phone.common.CallLogAsync;
     66 import com.android.phone.settings.SettingsConstants;
     67 import com.android.phone.vvm.CarrierVvmPackageInstalledReceiver;
     68 import com.android.services.telephony.sip.SipAccountRegistry;
     69 import com.android.services.telephony.sip.SipUtil;
     70 
     71 import java.io.FileDescriptor;
     72 import java.io.PrintWriter;
     73 
     74 /**
     75  * Global state for the telephony subsystem when running in the primary
     76  * phone process.
     77  */
     78 public class PhoneGlobals extends ContextWrapper {
     79     public static final String LOG_TAG = "PhoneGlobals";
     80 
     81     /**
     82      * Phone app-wide debug level:
     83      *   0 - no debug logging
     84      *   1 - normal debug logging if ro.debuggable is set (which is true in
     85      *       "eng" and "userdebug" builds but not "user" builds)
     86      *   2 - ultra-verbose debug logging
     87      *
     88      * Most individual classes in the phone app have a local DBG constant,
     89      * typically set to
     90      *   (PhoneApp.DBG_LEVEL >= 1) && (SystemProperties.getInt("ro.debuggable", 0) == 1)
     91      * or else
     92      *   (PhoneApp.DBG_LEVEL >= 2)
     93      * depending on the desired verbosity.
     94      *
     95      * ***** DO NOT SUBMIT WITH DBG_LEVEL > 0 *************
     96      */
     97     public static final int DBG_LEVEL = 0;
     98 
     99     private static final boolean DBG =
    100             (PhoneGlobals.DBG_LEVEL >= 1) && (SystemProperties.getInt("ro.debuggable", 0) == 1);
    101     private static final boolean VDBG = (PhoneGlobals.DBG_LEVEL >= 2);
    102 
    103     // Message codes; see mHandler below.
    104     private static final int EVENT_SIM_NETWORK_LOCKED = 3;
    105     private static final int EVENT_SIM_STATE_CHANGED = 8;
    106     private static final int EVENT_DATA_ROAMING_DISCONNECTED = 10;
    107     private static final int EVENT_DATA_ROAMING_OK = 11;
    108     private static final int EVENT_UNSOL_CDMA_INFO_RECORD = 12;
    109     private static final int EVENT_RESTART_SIP = 13;
    110     private static final int EVENT_DATA_ROAMING_SETTINGS_CHANGED = 14;
    111     private static final int EVENT_MOBILE_DATA_SETTINGS_CHANGED = 15;
    112 
    113     // The MMI codes are also used by the InCallScreen.
    114     public static final int MMI_INITIATE = 51;
    115     public static final int MMI_COMPLETE = 52;
    116     public static final int MMI_CANCEL = 53;
    117     // Don't use message codes larger than 99 here; those are reserved for
    118     // the individual Activities of the Phone UI.
    119 
    120     public static final int AIRPLANE_ON = 1;
    121     public static final int AIRPLANE_OFF = 0;
    122 
    123     /**
    124      * Allowable values for the wake lock code.
    125      *   SLEEP means the device can be put to sleep.
    126      *   PARTIAL means wake the processor, but we display can be kept off.
    127      *   FULL means wake both the processor and the display.
    128      */
    129     public enum WakeState {
    130         SLEEP,
    131         PARTIAL,
    132         FULL
    133     }
    134 
    135     private static PhoneGlobals sMe;
    136 
    137     // A few important fields we expose to the rest of the package
    138     // directly (rather than thru set/get methods) for efficiency.
    139     CallController callController;
    140     CallManager mCM;
    141     CallNotifier notifier;
    142     CallerInfoCache callerInfoCache;
    143     NotificationMgr notificationMgr;
    144     public PhoneInterfaceManager phoneMgr;
    145     CarrierConfigLoader configLoader;
    146 
    147     private CallGatewayManager callGatewayManager;
    148     private Phone phoneInEcm;
    149 
    150     static boolean sVoiceCapable = true;
    151 
    152     // TODO: Remove, no longer used.
    153     CdmaPhoneCallState cdmaPhoneCallState;
    154 
    155     // The currently-active PUK entry activity and progress dialog.
    156     // Normally, these are the Emergency Dialer and the subsequent
    157     // progress dialog.  null if there is are no such objects in
    158     // the foreground.
    159     private Activity mPUKEntryActivity;
    160     private ProgressDialog mPUKEntryProgressDialog;
    161 
    162     private boolean mNoDataDueToRoaming = false;
    163 
    164     private WakeState mWakeState = WakeState.SLEEP;
    165 
    166     private PowerManager mPowerManager;
    167     private PowerManager.WakeLock mWakeLock;
    168     private PowerManager.WakeLock mPartialWakeLock;
    169     private KeyguardManager mKeyguardManager;
    170 
    171     private UpdateLock mUpdateLock;
    172 
    173     private int mDefaultDataSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
    174     private final LocalLog mDataRoamingNotifLog = new LocalLog(50);
    175 
    176     // Broadcast receiver for various intent broadcasts (see onCreate())
    177     private final BroadcastReceiver mReceiver = new PhoneAppBroadcastReceiver();
    178     // Broadcast receiver for SIP based intents (see onCreate())
    179     private final SipReceiver mSipReceiver = new SipReceiver();
    180 
    181     private final CarrierVvmPackageInstalledReceiver mCarrierVvmPackageInstalledReceiver =
    182             new CarrierVvmPackageInstalledReceiver();
    183 
    184     private final SettingsObserver mSettingsObserver;
    185 
    186     Handler mHandler = new Handler() {
    187         @Override
    188         public void handleMessage(Message msg) {
    189             PhoneConstants.State phoneState;
    190             if (VDBG) Log.v(LOG_TAG, "event=" + msg.what);
    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 SipIncomingCallReceiver
    251                     // upon BOOT_COMPLETED.
    252                     UserManager userManager = UserManager.get(sMe);
    253                     if (userManager != null && userManager.isUserUnlocked()) {
    254                         SipUtil.startSipService();
    255                     }
    256                     break;
    257                 case EVENT_DATA_ROAMING_SETTINGS_CHANGED:
    258                 case EVENT_MOBILE_DATA_SETTINGS_CHANGED:
    259                     updateDataRoamingStatus();
    260                     break;
    261             }
    262         }
    263     };
    264 
    265     public PhoneGlobals(Context context) {
    266         super(context);
    267         sMe = this;
    268         mSettingsObserver = new SettingsObserver(context, mHandler);
    269     }
    270 
    271     public void onCreate() {
    272         if (VDBG) Log.v(LOG_TAG, "onCreate()...");
    273 
    274         ContentResolver resolver = getContentResolver();
    275 
    276         // Cache the "voice capable" flag.
    277         // This flag currently comes from a resource (which is
    278         // overrideable on a per-product basis):
    279         sVoiceCapable =
    280                 getResources().getBoolean(com.android.internal.R.bool.config_voice_capable);
    281         // ...but this might eventually become a PackageManager "system
    282         // feature" instead, in which case we'd do something like:
    283         // sVoiceCapable =
    284         //   getPackageManager().hasSystemFeature(PackageManager.FEATURE_TELEPHONY_VOICE_CALLS);
    285 
    286         if (mCM == null) {
    287             // Initialize the telephony framework
    288             PhoneFactory.makeDefaultPhones(this);
    289 
    290             // Start TelephonyDebugService After the default phone is created.
    291             Intent intent = new Intent(this, TelephonyDebugService.class);
    292             startService(intent);
    293 
    294             mCM = CallManager.getInstance();
    295             for (Phone phone : PhoneFactory.getPhones()) {
    296                 mCM.registerPhone(phone);
    297             }
    298 
    299             // Create the NotificationMgr singleton, which is used to display
    300             // status bar icons and control other status bar behavior.
    301             notificationMgr = NotificationMgr.init(this);
    302 
    303             // If PhoneGlobals has crashed and is being restarted, then restart.
    304             mHandler.sendEmptyMessage(EVENT_RESTART_SIP);
    305 
    306             // Create an instance of CdmaPhoneCallState and initialize it to IDLE
    307             cdmaPhoneCallState = new CdmaPhoneCallState();
    308             cdmaPhoneCallState.CdmaPhoneCallStateInit();
    309 
    310             // before registering for phone state changes
    311             mPowerManager = (PowerManager) getSystemService(Context.POWER_SERVICE);
    312             mWakeLock = mPowerManager.newWakeLock(PowerManager.FULL_WAKE_LOCK, LOG_TAG);
    313             // lock used to keep the processor awake, when we don't care for the display.
    314             mPartialWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK
    315                     | PowerManager.ON_AFTER_RELEASE, LOG_TAG);
    316 
    317             mKeyguardManager = (KeyguardManager) getSystemService(Context.KEYGUARD_SERVICE);
    318 
    319             // Get UpdateLock to suppress system-update related events (e.g. dialog show-up)
    320             // during phone calls.
    321             mUpdateLock = new UpdateLock("phone");
    322 
    323             if (DBG) Log.d(LOG_TAG, "onCreate: mUpdateLock: " + mUpdateLock);
    324 
    325             CallLogger callLogger = new CallLogger(this, new CallLogAsync());
    326 
    327             callGatewayManager = CallGatewayManager.getInstance();
    328 
    329             // Create the CallController singleton, which is the interface
    330             // to the telephony layer for user-initiated telephony functionality
    331             // (like making outgoing calls.)
    332             callController = CallController.init(this, callLogger, callGatewayManager);
    333 
    334             // Create the CallerInfoCache singleton, which remembers custom ring tone and
    335             // send-to-voicemail settings.
    336             //
    337             // The asynchronous caching will start just after this call.
    338             callerInfoCache = CallerInfoCache.init(this);
    339 
    340             phoneMgr = PhoneInterfaceManager.init(this, PhoneFactory.getDefaultPhone());
    341 
    342             configLoader = CarrierConfigLoader.init(this);
    343 
    344             // Create the CallNotifier singleton, which handles
    345             // asynchronous events from the telephony layer (like
    346             // launching the incoming-call UI when an incoming call comes
    347             // in.)
    348             notifier = CallNotifier.init(this);
    349 
    350             PhoneUtils.registerIccStatus(mHandler, EVENT_SIM_NETWORK_LOCKED);
    351 
    352             // register for MMI/USSD
    353             mCM.registerForMmiComplete(mHandler, MMI_COMPLETE, null);
    354 
    355             // register connection tracking to PhoneUtils
    356             PhoneUtils.initializeConnectionHandler(mCM);
    357 
    358             // Register for misc other intent broadcasts.
    359             IntentFilter intentFilter =
    360                     new IntentFilter(Intent.ACTION_AIRPLANE_MODE_CHANGED);
    361             intentFilter.addAction(TelephonyIntents.ACTION_SIM_STATE_CHANGED);
    362             intentFilter.addAction(TelephonyIntents.ACTION_RADIO_TECHNOLOGY_CHANGED);
    363             intentFilter.addAction(TelephonyIntents.ACTION_SERVICE_STATE_CHANGED);
    364             intentFilter.addAction(TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED);
    365             intentFilter.addAction(TelephonyIntents.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED);
    366             intentFilter.addAction(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED);
    367             registerReceiver(mReceiver, intentFilter);
    368 
    369             IntentFilter sipIntentFilter = new IntentFilter(Intent.ACTION_BOOT_COMPLETED);
    370             sipIntentFilter.addAction(SipManager.ACTION_SIP_SERVICE_UP);
    371             sipIntentFilter.addAction(SipManager.ACTION_SIP_CALL_OPTION_CHANGED);
    372             sipIntentFilter.addAction(SipManager.ACTION_SIP_REMOVE_PHONE);
    373             registerReceiver(mSipReceiver, sipIntentFilter);
    374 
    375             mCarrierVvmPackageInstalledReceiver.register(this);
    376 
    377             //set the default values for the preferences in the phone.
    378             PreferenceManager.setDefaultValues(this, R.xml.network_setting_fragment, false);
    379 
    380             PreferenceManager.setDefaultValues(this, R.xml.call_feature_setting, false);
    381 
    382             // Make sure the audio mode (along with some
    383             // audio-mode-related state of our own) is initialized
    384             // correctly, given the current state of the phone.
    385             PhoneUtils.setAudioMode(mCM);
    386         }
    387 
    388         // XXX pre-load the SimProvider so that it's ready
    389         resolver.getType(Uri.parse("content://icc/adn"));
    390 
    391         // TODO: Register for Cdma Information Records
    392         // phone.registerCdmaInformationRecord(mHandler, EVENT_UNSOL_CDMA_INFO_RECORD, null);
    393 
    394         // Read HAC settings and configure audio hardware
    395         if (getResources().getBoolean(R.bool.hac_enabled)) {
    396             int hac = android.provider.Settings.System.getInt(
    397                     getContentResolver(),
    398                     android.provider.Settings.System.HEARING_AID,
    399                     0);
    400             AudioManager audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
    401             audioManager.setParameter(SettingsConstants.HAC_KEY,
    402                     hac == SettingsConstants.HAC_ENABLED
    403                             ? SettingsConstants.HAC_VAL_ON : SettingsConstants.HAC_VAL_OFF);
    404         }
    405     }
    406 
    407     /**
    408      * Returns the singleton instance of the PhoneApp.
    409      */
    410     public static PhoneGlobals getInstance() {
    411         if (sMe == null) {
    412             throw new IllegalStateException("No PhoneGlobals here!");
    413         }
    414         return sMe;
    415     }
    416 
    417     /**
    418      * Returns the singleton instance of the PhoneApp if running as the
    419      * primary user, otherwise null.
    420      */
    421     static PhoneGlobals getInstanceIfPrimary() {
    422         return sMe;
    423     }
    424 
    425     /**
    426      * Returns the default phone.
    427      *
    428      * WARNING: This method should be used carefully, now that there may be multiple phones.
    429      */
    430     public static Phone getPhone() {
    431         return PhoneFactory.getDefaultPhone();
    432     }
    433 
    434     public static Phone getPhone(int subId) {
    435         return PhoneFactory.getPhone(SubscriptionManager.getPhoneId(subId));
    436     }
    437 
    438     /* package */ CallManager getCallManager() {
    439         return mCM;
    440     }
    441 
    442     public PersistableBundle getCarrierConfig() {
    443         return getCarrierConfigForSubId(SubscriptionManager.getDefaultSubscriptionId());
    444     }
    445 
    446     public PersistableBundle getCarrierConfigForSubId(int subId) {
    447         return configLoader.getConfigForSubId(subId);
    448     }
    449 
    450     private void registerSettingsObserver() {
    451         mSettingsObserver.unobserve();
    452         String dataRoamingSetting = Settings.Global.DATA_ROAMING;
    453         String mobileDataSetting = Settings.Global.MOBILE_DATA;
    454         if (TelephonyManager.getDefault().getSimCount() > 1) {
    455             int subId = mDefaultDataSubId;
    456             if (subId != SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
    457                 dataRoamingSetting += subId;
    458                 mobileDataSetting += subId;
    459             }
    460         }
    461 
    462         // Listen for user data roaming setting changed event
    463         mSettingsObserver.observe(Settings.Global.getUriFor(dataRoamingSetting),
    464                 EVENT_DATA_ROAMING_SETTINGS_CHANGED);
    465 
    466         // Listen for mobile data setting changed event
    467         mSettingsObserver.observe(Settings.Global.getUriFor(mobileDataSetting),
    468                 EVENT_MOBILE_DATA_SETTINGS_CHANGED);
    469     }
    470 
    471     /**
    472      * Sets the activity responsible for un-PUK-blocking the device
    473      * so that we may close it when we receive a positive result.
    474      * mPUKEntryActivity is also used to indicate to the device that
    475      * we are trying to un-PUK-lock the phone. In other words, iff
    476      * it is NOT null, then we are trying to unlock and waiting for
    477      * the SIM to move to READY state.
    478      *
    479      * @param activity is the activity to close when PUK has
    480      * finished unlocking. Can be set to null to indicate the unlock
    481      * or SIM READYing process is over.
    482      */
    483     void setPukEntryActivity(Activity activity) {
    484         mPUKEntryActivity = activity;
    485     }
    486 
    487     Activity getPUKEntryActivity() {
    488         return mPUKEntryActivity;
    489     }
    490 
    491     /**
    492      * Sets the dialog responsible for notifying the user of un-PUK-
    493      * blocking - SIM READYing progress, so that we may dismiss it
    494      * when we receive a positive result.
    495      *
    496      * @param dialog indicates the progress dialog informing the user
    497      * of the state of the device.  Dismissed upon completion of
    498      * READYing process
    499      */
    500     void setPukEntryProgressDialog(ProgressDialog dialog) {
    501         mPUKEntryProgressDialog = dialog;
    502     }
    503 
    504     /**
    505      * Controls whether or not the screen is allowed to sleep.
    506      *
    507      * Once sleep is allowed (WakeState is SLEEP), it will rely on the
    508      * settings for the poke lock to determine when to timeout and let
    509      * the device sleep {@link PhoneGlobals#setScreenTimeout}.
    510      *
    511      * @param ws tells the device to how to wake.
    512      */
    513     /* package */ void requestWakeState(WakeState ws) {
    514         if (VDBG) Log.d(LOG_TAG, "requestWakeState(" + ws + ")...");
    515         synchronized (this) {
    516             if (mWakeState != ws) {
    517                 switch (ws) {
    518                     case PARTIAL:
    519                         // acquire the processor wake lock, and release the FULL
    520                         // lock if it is being held.
    521                         mPartialWakeLock.acquire();
    522                         if (mWakeLock.isHeld()) {
    523                             mWakeLock.release();
    524                         }
    525                         break;
    526                     case FULL:
    527                         // acquire the full wake lock, and release the PARTIAL
    528                         // lock if it is being held.
    529                         mWakeLock.acquire();
    530                         if (mPartialWakeLock.isHeld()) {
    531                             mPartialWakeLock.release();
    532                         }
    533                         break;
    534                     case SLEEP:
    535                     default:
    536                         // release both the PARTIAL and FULL locks.
    537                         if (mWakeLock.isHeld()) {
    538                             mWakeLock.release();
    539                         }
    540                         if (mPartialWakeLock.isHeld()) {
    541                             mPartialWakeLock.release();
    542                         }
    543                         break;
    544                 }
    545                 mWakeState = ws;
    546             }
    547         }
    548     }
    549 
    550     /**
    551      * If we are not currently keeping the screen on, then poke the power
    552      * manager to wake up the screen for the user activity timeout duration.
    553      */
    554     /* package */ void wakeUpScreen() {
    555         synchronized (this) {
    556             if (mWakeState == WakeState.SLEEP) {
    557                 if (DBG) Log.d(LOG_TAG, "pulse screen lock");
    558                 mPowerManager.wakeUp(SystemClock.uptimeMillis(), "android.phone:WAKE");
    559             }
    560         }
    561     }
    562 
    563     /**
    564      * Sets the wake state and screen timeout based on the current state
    565      * of the phone, and the current state of the in-call UI.
    566      *
    567      * This method is a "UI Policy" wrapper around
    568      * {@link PhoneGlobals#requestWakeState} and {@link PhoneGlobals#setScreenTimeout}.
    569      *
    570      * It's safe to call this method regardless of the state of the Phone
    571      * (e.g. whether or not it's idle), and regardless of the state of the
    572      * Phone UI (e.g. whether or not the InCallScreen is active.)
    573      */
    574     /* package */ void updateWakeState() {
    575         PhoneConstants.State state = mCM.getState();
    576 
    577         // True if the speakerphone is in use.  (If so, we *always* use
    578         // the default timeout.  Since the user is obviously not holding
    579         // the phone up to his/her face, we don't need to worry about
    580         // false touches, and thus don't need to turn the screen off so
    581         // aggressively.)
    582         // Note that we need to make a fresh call to this method any
    583         // time the speaker state changes.  (That happens in
    584         // PhoneUtils.turnOnSpeaker().)
    585         boolean isSpeakerInUse = (state == PhoneConstants.State.OFFHOOK) && PhoneUtils.isSpeakerOn(this);
    586 
    587         // TODO (bug 1440854): The screen timeout *might* also need to
    588         // depend on the bluetooth state, but this isn't as clear-cut as
    589         // the speaker state (since while using BT it's common for the
    590         // user to put the phone straight into a pocket, in which case the
    591         // timeout should probably still be short.)
    592 
    593         // Decide whether to force the screen on or not.
    594         //
    595         // Force the screen to be on if the phone is ringing or dialing,
    596         // or if we're displaying the "Call ended" UI for a connection in
    597         // the "disconnected" state.
    598         // However, if the phone is disconnected while the user is in the
    599         // middle of selecting a quick response message, we should not force
    600         // the screen to be on.
    601         //
    602         boolean isRinging = (state == PhoneConstants.State.RINGING);
    603         boolean isDialing = (mCM.getFgPhone().getForegroundCall().getState() == Call.State.DIALING);
    604         boolean keepScreenOn = isRinging || isDialing;
    605         // keepScreenOn == true means we'll hold a full wake lock:
    606         requestWakeState(keepScreenOn ? WakeState.FULL : WakeState.SLEEP);
    607     }
    608 
    609     KeyguardManager getKeyguardManager() {
    610         return mKeyguardManager;
    611     }
    612 
    613     private void onMMIComplete(AsyncResult r) {
    614         if (VDBG) Log.d(LOG_TAG, "onMMIComplete()...");
    615         MmiCode mmiCode = (MmiCode) r.result;
    616         PhoneUtils.displayMMIComplete(mmiCode.getPhone(), getInstance(), mmiCode, null, null);
    617     }
    618 
    619     private void initForNewRadioTechnology() {
    620         if (DBG) Log.d(LOG_TAG, "initForNewRadioTechnology...");
    621         notifier.updateCallNotifierRegistrationsAfterRadioTechnologyChange();
    622     }
    623 
    624     private void handleAirplaneModeChange(Context context, int newMode) {
    625         int cellState = Settings.Global.getInt(context.getContentResolver(),
    626                 Settings.Global.CELL_ON, PhoneConstants.CELL_ON_FLAG);
    627         boolean isAirplaneNewlyOn = (newMode == 1);
    628         switch (cellState) {
    629             case PhoneConstants.CELL_OFF_FLAG:
    630                 // Airplane mode does not affect the cell radio if user
    631                 // has turned it off.
    632                 break;
    633             case PhoneConstants.CELL_ON_FLAG:
    634                 maybeTurnCellOff(context, isAirplaneNewlyOn);
    635                 break;
    636             case PhoneConstants.CELL_OFF_DUE_TO_AIRPLANE_MODE_FLAG:
    637                 maybeTurnCellOn(context, isAirplaneNewlyOn);
    638                 break;
    639         }
    640     }
    641 
    642     /*
    643      * Returns true if the radio must be turned off when entering airplane mode.
    644      */
    645     private boolean isCellOffInAirplaneMode(Context context) {
    646         String airplaneModeRadios = Settings.Global.getString(context.getContentResolver(),
    647                 Settings.Global.AIRPLANE_MODE_RADIOS);
    648         return airplaneModeRadios == null
    649                 || airplaneModeRadios.contains(Settings.Global.RADIO_CELL);
    650     }
    651 
    652     private void setRadioPowerOff(Context context) {
    653         Log.i(LOG_TAG, "Turning radio off - airplane");
    654         Settings.Global.putInt(context.getContentResolver(), Settings.Global.CELL_ON,
    655                  PhoneConstants.CELL_OFF_DUE_TO_AIRPLANE_MODE_FLAG);
    656         SystemProperties.set("persist.radio.airplane_mode_on", "1");
    657         Settings.Global.putInt(getContentResolver(), Settings.Global.ENABLE_CELLULAR_ON_BOOT, 0);
    658         PhoneUtils.setRadioPower(false);
    659     }
    660 
    661     private void setRadioPowerOn(Context context) {
    662         Log.i(LOG_TAG, "Turning radio on - airplane");
    663         Settings.Global.putInt(context.getContentResolver(), Settings.Global.CELL_ON,
    664                 PhoneConstants.CELL_ON_FLAG);
    665         Settings.Global.putInt(getContentResolver(), Settings.Global.ENABLE_CELLULAR_ON_BOOT,
    666                 1);
    667         SystemProperties.set("persist.radio.airplane_mode_on", "0");
    668         PhoneUtils.setRadioPower(true);
    669     }
    670 
    671     private void maybeTurnCellOff(Context context, boolean isAirplaneNewlyOn) {
    672         if (isAirplaneNewlyOn) {
    673             // If we are trying to turn off the radio, make sure there are no active
    674             // emergency calls.  If there are, switch airplane mode back to off.
    675             if (PhoneUtils.isInEmergencyCall(mCM)) {
    676                 // Switch airplane mode back to off.
    677                 ConnectivityManager.from(this).setAirplaneMode(false);
    678                 Toast.makeText(this, R.string.radio_off_during_emergency_call, Toast.LENGTH_LONG)
    679                         .show();
    680                 Log.i(LOG_TAG, "Ignoring airplane mode: emergency call. Turning airplane off");
    681             } else if (isCellOffInAirplaneMode(context)) {
    682                 setRadioPowerOff(context);
    683             } else {
    684                 Log.i(LOG_TAG, "Ignoring airplane mode: settings prevent cell radio power off");
    685             }
    686         }
    687     }
    688 
    689     private void maybeTurnCellOn(Context context, boolean isAirplaneNewlyOn) {
    690         if (!isAirplaneNewlyOn) {
    691             setRadioPowerOn(context);
    692         }
    693     }
    694 
    695     /**
    696      * Receiver for misc intent broadcasts the Phone app cares about.
    697      */
    698     private class PhoneAppBroadcastReceiver extends BroadcastReceiver {
    699         @Override
    700         public void onReceive(Context context, Intent intent) {
    701             String action = intent.getAction();
    702             if (action.equals(Intent.ACTION_AIRPLANE_MODE_CHANGED)) {
    703                 int airplaneMode = Settings.Global.getInt(getContentResolver(),
    704                         Settings.Global.AIRPLANE_MODE_ON, AIRPLANE_OFF);
    705                 // Treat any non-OFF values as ON.
    706                 if (airplaneMode != AIRPLANE_OFF) {
    707                     airplaneMode = AIRPLANE_ON;
    708                 }
    709                 handleAirplaneModeChange(context, airplaneMode);
    710             } else if ((action.equals(TelephonyIntents.ACTION_SIM_STATE_CHANGED)) &&
    711                     (mPUKEntryActivity != null)) {
    712                 // if an attempt to un-PUK-lock the device was made, while we're
    713                 // receiving this state change notification, notify the handler.
    714                 // NOTE: This is ONLY triggered if an attempt to un-PUK-lock has
    715                 // been attempted.
    716                 mHandler.sendMessage(mHandler.obtainMessage(EVENT_SIM_STATE_CHANGED,
    717                         intent.getStringExtra(IccCardConstants.INTENT_KEY_ICC_STATE)));
    718             } else if (action.equals(TelephonyIntents.ACTION_RADIO_TECHNOLOGY_CHANGED)) {
    719                 String newPhone = intent.getStringExtra(PhoneConstants.PHONE_NAME_KEY);
    720                 Log.d(LOG_TAG, "Radio technology switched. Now " + newPhone + " is active.");
    721                 initForNewRadioTechnology();
    722             } else if (action.equals(TelephonyIntents.ACTION_SERVICE_STATE_CHANGED)) {
    723                 handleServiceStateChanged(intent);
    724             } else if (action.equals(TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED)) {
    725                 int phoneId = intent.getIntExtra(PhoneConstants.PHONE_KEY, 0);
    726                 phoneInEcm = PhoneFactory.getPhone(phoneId);
    727                 Log.d(LOG_TAG, "Emergency Callback Mode. phoneId:" + phoneId);
    728                 if (phoneInEcm != null) {
    729                     if (TelephonyCapabilities.supportsEcm(phoneInEcm)) {
    730                         Log.d(LOG_TAG, "Emergency Callback Mode arrived in PhoneApp.");
    731                         // Start Emergency Callback Mode service
    732                         if (intent.getBooleanExtra("phoneinECMState", false)) {
    733                             context.startService(new Intent(context,
    734                                     EmergencyCallbackModeService.class));
    735                         } else {
    736                             phoneInEcm = null;
    737                         }
    738                     } else {
    739                         // It doesn't make sense to get ACTION_EMERGENCY_CALLBACK_MODE_CHANGED
    740                         // on a device that doesn't support ECM in the first place.
    741                         Log.e(LOG_TAG, "Got ACTION_EMERGENCY_CALLBACK_MODE_CHANGED, but "
    742                                 + "ECM isn't supported for phone: " + phoneInEcm.getPhoneName());
    743                         phoneInEcm = null;
    744                     }
    745                 } else {
    746                     Log.w(LOG_TAG, "phoneInEcm is null.");
    747                 }
    748             } else if (action.equals(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED)) {
    749                 // Roaming status could be overridden by carrier config, so we need to update it.
    750                 if (VDBG) Log.v(LOG_TAG, "carrier config changed.");
    751                 updateDataRoamingStatus();
    752             } else if (action.equals(TelephonyIntents.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED)) {
    753                 // We also need to pay attention when default data subscription changes.
    754                 if (VDBG) Log.v(LOG_TAG, "default data sub changed.");
    755                 mDefaultDataSubId = SubscriptionManager.getDefaultDataSubscriptionId();
    756                 registerSettingsObserver();
    757                 Phone phone = getPhone(mDefaultDataSubId);
    758                 if (phone != null) {
    759                     updateDataRoamingStatus();
    760                 }
    761             }
    762         }
    763     }
    764 
    765     private class SipReceiver extends BroadcastReceiver {
    766 
    767         @Override
    768         public void onReceive(Context context, Intent intent) {
    769             String action = intent.getAction();
    770 
    771             SipAccountRegistry sipAccountRegistry = SipAccountRegistry.getInstance();
    772             if (action.equals(Intent.ACTION_BOOT_COMPLETED)) {
    773                 SipUtil.startSipService();
    774             } else if (action.equals(SipManager.ACTION_SIP_SERVICE_UP)
    775                     || action.equals(SipManager.ACTION_SIP_CALL_OPTION_CHANGED)) {
    776                 sipAccountRegistry.setup(context);
    777             } else if (action.equals(SipManager.ACTION_SIP_REMOVE_PHONE)) {
    778                 if (DBG) {
    779                     Log.d(LOG_TAG, "SIP_REMOVE_PHONE "
    780                             + intent.getStringExtra(SipManager.EXTRA_LOCAL_URI));
    781                 }
    782                 sipAccountRegistry.removeSipProfile(intent.getStringExtra(
    783                         SipManager.EXTRA_LOCAL_URI));
    784             } else {
    785                 if (DBG) Log.d(LOG_TAG, "onReceive, action not processed: " + action);
    786             }
    787         }
    788     }
    789 
    790     private void handleServiceStateChanged(Intent intent) {
    791         /**
    792          * This used to handle updating EriTextWidgetProvider this routine
    793          * and and listening for ACTION_SERVICE_STATE_CHANGED intents could
    794          * be removed. But leaving just in case it might be needed in the near
    795          * future.
    796          */
    797 
    798         if (VDBG) Log.v(LOG_TAG, "handleServiceStateChanged");
    799         // If service just returned, start sending out the queued messages
    800         Bundle extras = intent.getExtras();
    801         if (extras != null) {
    802             ServiceState ss = ServiceState.newFromBundle(extras);
    803             if (ss != null) {
    804                 int state = ss.getState();
    805                 int subId = intent.getIntExtra(PhoneConstants.SUBSCRIPTION_KEY,
    806                         SubscriptionManager.INVALID_SUBSCRIPTION_ID);
    807                 notificationMgr.updateNetworkSelection(state, subId);
    808 
    809                 if (VDBG) {
    810                     Log.v(LOG_TAG, "subId=" + subId + ",mDefaultDataSubId="
    811                             + mDefaultDataSubId + ",ss roaming=" + ss.getDataRoaming());
    812                 }
    813                 if (subId == mDefaultDataSubId) {
    814                     updateDataRoamingStatus();
    815                 }
    816             }
    817         }
    818     }
    819 
    820     /**
    821      * When roaming, if mobile data cannot be established due to data roaming not enabled, we need
    822      * to notify the user so they can enable it through settings. Vise versa if the condition
    823      * changes, we need to dismiss the notification.
    824      */
    825     private void updateDataRoamingStatus() {
    826         if (VDBG) Log.v(LOG_TAG, "updateDataRoamingStatus");
    827         Phone phone = getPhone(mDefaultDataSubId);
    828         if (phone == null) {
    829             Log.w(LOG_TAG, "Can't get phone with sub id = " + mDefaultDataSubId);
    830             return;
    831         }
    832 
    833         DataConnectionReasons reasons = new DataConnectionReasons();
    834         boolean dataAllowed = phone.isDataAllowed(reasons);
    835         mDataRoamingNotifLog.log("dataAllowed=" + dataAllowed + ", reasons=" + reasons);
    836         if (VDBG) Log.v(LOG_TAG, "dataAllowed=" + dataAllowed + ", reasons=" + reasons);
    837         if (!mNoDataDueToRoaming
    838                 && !dataAllowed
    839                 && reasons.containsOnly(DataDisallowedReasonType.ROAMING_DISABLED)) {
    840             // If the only reason of no data is data roaming disabled, then we notify the user
    841             // so the user can turn on data roaming.
    842             mNoDataDueToRoaming = true;
    843             Log.d(LOG_TAG, "Show roaming disconnected notification");
    844             mDataRoamingNotifLog.log("Show");
    845             mHandler.sendEmptyMessage(EVENT_DATA_ROAMING_DISCONNECTED);
    846         } else if (mNoDataDueToRoaming && (dataAllowed
    847                 || !reasons.containsOnly(DataDisallowedReasonType.ROAMING_DISABLED))) {
    848             // Otherwise dismiss the notification we showed earlier.
    849             mNoDataDueToRoaming = false;
    850             Log.d(LOG_TAG, "Dismiss roaming disconnected notification");
    851             mDataRoamingNotifLog.log("Hide. data allowed=" + dataAllowed + ", reasons=" + reasons);
    852             mHandler.sendEmptyMessage(EVENT_DATA_ROAMING_OK);
    853         }
    854     }
    855 
    856     public Phone getPhoneInEcm() {
    857         return phoneInEcm;
    858     }
    859 
    860     /**
    861      * Triggers a refresh of the message waiting (voicemail) indicator.
    862      *
    863      * @param subId the subscription id we should refresh the notification for.
    864      */
    865     public void refreshMwiIndicator(int subId) {
    866         notificationMgr.refreshMwi(subId);
    867     }
    868 
    869     /**
    870      * Dismisses the message waiting (voicemail) indicator.
    871      *
    872      * @param subId the subscription id we should dismiss the notification for.
    873      */
    874     public void clearMwiIndicator(int subId) {
    875         // Setting voiceMessageCount to 0 will remove the current notification and clear the system
    876         // cached value.
    877         Phone phone = getPhone(subId);
    878         if (phone == null) {
    879             Log.w(LOG_TAG, "clearMwiIndicator on null phone, subId:" + subId);
    880         } else {
    881             phone.setVoiceMessageCount(0);
    882         }
    883     }
    884 
    885     /**
    886      * Enables or disables the visual voicemail check for message waiting indicator. Default value
    887      * is true. MWI is the traditional voicemail notification which should be suppressed if visual
    888      * voicemail is active. {@link NotificationMgr#updateMwi(int, boolean, boolean)} currently
    889      * checks the {@link android.provider.VoicemailContract.Status#CONFIGURATION_STATE} to suppress
    890      * the MWI, but there are several issues. b/31229016 is a bug that when the device boots the
    891      * configuration state will be cleared and the MWI for voicemail that arrives when the device
    892      * is offline will be cleared, even if the account cannot be activated. A full solution will be
    893      * adding a setMwiEnabled() method and stop checking the configuration state, but that is too
    894      * risky at this moment. This is a temporary workaround to shut down the configuration state
    895      * check if visual voicemail cannot be activated.
    896      * <p>TODO(twyen): implement the setMwiEnabled() mentioned above.
    897      *
    898      * @param subId the account to set the enabled state
    899      */
    900     public void setShouldCheckVisualVoicemailConfigurationForMwi(int subId, boolean enabled) {
    901         notificationMgr.setShouldCheckVisualVoicemailConfigurationForMwi(subId, enabled);
    902     }
    903 
    904     /**
    905      * Dump the state of the object, add calls to other objects as desired.
    906      *
    907      * @param fd File descriptor
    908      * @param printWriter Print writer
    909      * @param args Arguments
    910      */
    911     public void dump(FileDescriptor fd, PrintWriter printWriter, String[] args) {
    912         IndentingPrintWriter pw = new IndentingPrintWriter(printWriter, "  ");
    913         pw.println("------- PhoneGlobals -------");
    914         pw.increaseIndent();
    915         pw.println("mNoDataDueToRoaming=" + mNoDataDueToRoaming);
    916         pw.println("mDefaultDataSubId=" + mDefaultDataSubId);
    917         pw.println("mDataRoamingNotifLog:");
    918         pw.increaseIndent();
    919         mDataRoamingNotifLog.dump(fd, pw, args);
    920         pw.decreaseIndent();
    921         pw.decreaseIndent();
    922         pw.println("------- End PhoneGlobals -------");
    923     }
    924 }
    925