• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.content.res.XmlResourceParser;
29 import android.media.AudioManager;
30 import android.net.ConnectivityManager;
31 import android.net.Uri;
32 import android.net.sip.SipManager;
33 import android.os.AsyncResult;
34 import android.os.Bundle;
35 import android.os.Handler;
36 import android.os.Message;
37 import android.os.PersistableBundle;
38 import android.os.PowerManager;
39 import android.os.SystemClock;
40 import android.os.SystemProperties;
41 import android.os.UpdateLock;
42 import android.os.UserManager;
43 import android.preference.PreferenceManager;
44 import android.provider.Settings;
45 import android.telecom.TelecomManager;
46 import android.telephony.AnomalyReporter;
47 import android.telephony.CarrierConfigManager;
48 import android.telephony.ServiceState;
49 import android.telephony.SubscriptionManager;
50 import android.telephony.TelephonyManager;
51 import android.telephony.data.ApnSetting;
52 import android.util.LocalLog;
53 import android.util.Log;
54 import android.widget.Toast;
55 
56 import com.android.internal.telephony.CallManager;
57 import com.android.internal.telephony.IccCardConstants;
58 import com.android.internal.telephony.MmiCode;
59 import com.android.internal.telephony.Phone;
60 import com.android.internal.telephony.PhoneConstants;
61 import com.android.internal.telephony.PhoneFactory;
62 import com.android.internal.telephony.SettingsObserver;
63 import com.android.internal.telephony.TelephonyCapabilities;
64 import com.android.internal.telephony.TelephonyComponentFactory;
65 import com.android.internal.telephony.TelephonyIntents;
66 import com.android.internal.telephony.dataconnection.DataConnectionReasons;
67 import com.android.internal.telephony.dataconnection.DataConnectionReasons.DataDisallowedReasonType;
68 import com.android.internal.util.IndentingPrintWriter;
69 import com.android.phone.settings.SettingsConstants;
70 import com.android.phone.vvm.CarrierVvmPackageInstalledReceiver;
71 import com.android.services.telephony.sip.SipAccountRegistry;
72 import com.android.services.telephony.sip.SipUtil;
73 
74 import java.io.FileDescriptor;
75 import java.io.PrintWriter;
76 
77 /**
78  * Global state for the telephony subsystem when running in the primary
79  * phone process.
80  */
81 public class PhoneGlobals extends ContextWrapper {
82     public static final String LOG_TAG = "PhoneGlobals";
83 
84     /**
85      * Phone app-wide debug level:
86      *   0 - no debug logging
87      *   1 - normal debug logging if ro.debuggable is set (which is true in
88      *       "eng" and "userdebug" builds but not "user" builds)
89      *   2 - ultra-verbose debug logging
90      *
91      * Most individual classes in the phone app have a local DBG constant,
92      * typically set to
93      *   (PhoneApp.DBG_LEVEL >= 1) && (SystemProperties.getInt("ro.debuggable", 0) == 1)
94      * or else
95      *   (PhoneApp.DBG_LEVEL >= 2)
96      * depending on the desired verbosity.
97      *
98      * ***** DO NOT SUBMIT WITH DBG_LEVEL > 0 *************
99      */
100     public static final int DBG_LEVEL = 0;
101 
102     private static final boolean DBG =
103             (PhoneGlobals.DBG_LEVEL >= 1) && (SystemProperties.getInt("ro.debuggable", 0) == 1);
104     private static final boolean VDBG = (PhoneGlobals.DBG_LEVEL >= 2);
105 
106     // Message codes; see mHandler below.
107     private static final int EVENT_SIM_NETWORK_LOCKED = 3;
108     private static final int EVENT_SIM_STATE_CHANGED = 8;
109     private static final int EVENT_DATA_ROAMING_DISCONNECTED = 10;
110     private static final int EVENT_DATA_ROAMING_OK = 11;
111     private static final int EVENT_UNSOL_CDMA_INFO_RECORD = 12;
112     private static final int EVENT_RESTART_SIP = 13;
113     private static final int EVENT_DATA_ROAMING_SETTINGS_CHANGED = 14;
114     private static final int EVENT_MOBILE_DATA_SETTINGS_CHANGED = 15;
115 
116     // The MMI codes are also used by the InCallScreen.
117     public static final int MMI_INITIATE = 51;
118     public static final int MMI_COMPLETE = 52;
119     public static final int MMI_CANCEL = 53;
120     // Don't use message codes larger than 99 here; those are reserved for
121     // the individual Activities of the Phone UI.
122 
123     public static final int AIRPLANE_ON = 1;
124     public static final int AIRPLANE_OFF = 0;
125 
126     /**
127      * Allowable values for the wake lock code.
128      *   SLEEP means the device can be put to sleep.
129      *   PARTIAL means wake the processor, but we display can be kept off.
130      *   FULL means wake both the processor and the display.
131      */
132     public enum WakeState {
133         SLEEP,
134         PARTIAL,
135         FULL
136     }
137 
138     private static PhoneGlobals sMe;
139 
140     CallManager mCM;
141     CallNotifier notifier;
142     CallerInfoCache callerInfoCache;
143     NotificationMgr notificationMgr;
144     public PhoneInterfaceManager phoneMgr;
145     CarrierConfigLoader configLoader;
146 
147     private Phone phoneInEcm;
148 
149     static boolean sVoiceCapable = true;
150 
151     // TODO: Remove, no longer used.
152     CdmaPhoneCallState cdmaPhoneCallState;
153 
154     // The currently-active PUK entry activity and progress dialog.
155     // Normally, these are the Emergency Dialer and the subsequent
156     // progress dialog.  null if there is are no such objects in
157     // the foreground.
158     private Activity mPUKEntryActivity;
159     private ProgressDialog mPUKEntryProgressDialog;
160 
161     private boolean mNoDataDueToRoaming = false;
162 
163     private WakeState mWakeState = WakeState.SLEEP;
164 
165     private PowerManager mPowerManager;
166     private PowerManager.WakeLock mWakeLock;
167     private PowerManager.WakeLock mPartialWakeLock;
168     private KeyguardManager mKeyguardManager;
169 
170     private UpdateLock mUpdateLock;
171 
172     private int mDefaultDataSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
173     private final LocalLog mDataRoamingNotifLog = new LocalLog(50);
174 
175     // Broadcast receiver for various intent broadcasts (see onCreate())
176     private final BroadcastReceiver mReceiver = new PhoneAppBroadcastReceiver();
177     // Broadcast receiver for SIP based intents (see onCreate())
178     private final SipReceiver mSipReceiver = new SipReceiver();
179 
180     private final CarrierVvmPackageInstalledReceiver mCarrierVvmPackageInstalledReceiver =
181             new CarrierVvmPackageInstalledReceiver();
182 
183     private final SettingsObserver mSettingsObserver;
184 
185     Handler mHandler = new Handler() {
186         @Override
187         public void handleMessage(Message msg) {
188             PhoneConstants.State phoneState;
189             if (VDBG) Log.v(LOG_TAG, "event=" + msg.what);
190             switch (msg.what) {
191                 // TODO: This event should be handled by the lock screen, just
192                 // like the "SIM missing" and "Sim locked" cases (bug 1804111).
193                 case EVENT_SIM_NETWORK_LOCKED:
194                     if (getCarrierConfig().getBoolean(
195                             CarrierConfigManager.KEY_IGNORE_SIM_NETWORK_LOCKED_EVENTS_BOOL)) {
196                         // Some products don't have the concept of a "SIM network lock"
197                         Log.i(LOG_TAG, "Ignoring EVENT_SIM_NETWORK_LOCKED event; "
198                               + "not showing 'SIM network unlock' PIN entry screen");
199                     } else {
200                         // Normal case: show the "SIM network unlock" PIN entry screen.
201                         // The user won't be able to do anything else until
202                         // they enter a valid SIM network PIN.
203                         Log.i(LOG_TAG, "show sim depersonal panel");
204                         Phone phone = (Phone) ((AsyncResult) msg.obj).userObj;
205                         IccNetworkDepersonalizationPanel.showDialog(phone);
206                     }
207                     break;
208 
209                 case EVENT_DATA_ROAMING_DISCONNECTED:
210                     notificationMgr.showDataDisconnectedRoaming(msg.arg1);
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                             || msg.obj.equals(IccCardConstants.INTENT_VALUE_ICC_LOADED)) {
231                         // when the right event is triggered and there
232                         // are UI objects in the foreground, we close
233                         // them to display the lock panel.
234                         if (mPUKEntryActivity != null) {
235                             mPUKEntryActivity.finish();
236                             mPUKEntryActivity = null;
237                         }
238                         if (mPUKEntryProgressDialog != null) {
239                             mPUKEntryProgressDialog.dismiss();
240                             mPUKEntryProgressDialog = null;
241                         }
242                     }
243                     break;
244 
245                 case EVENT_UNSOL_CDMA_INFO_RECORD:
246                     //TODO: handle message here;
247                     break;
248                 case EVENT_RESTART_SIP:
249                     // This should only run if the Phone process crashed and was restarted. We do
250                     // not want this running if the device is still in the FBE encrypted state.
251                     // This is the same procedure that is triggered in the SipIncomingCallReceiver
252                     // upon BOOT_COMPLETED.
253                     UserManager userManager = UserManager.get(sMe);
254                     if (userManager != null && userManager.isUserUnlocked()) {
255                         SipUtil.startSipService();
256                     }
257                     break;
258                 case EVENT_DATA_ROAMING_SETTINGS_CHANGED:
259                 case EVENT_MOBILE_DATA_SETTINGS_CHANGED:
260                     updateDataRoamingStatus();
261                     break;
262             }
263         }
264     };
265 
PhoneGlobals(Context context)266     public PhoneGlobals(Context context) {
267         super(context);
268         sMe = this;
269         mSettingsObserver = new SettingsObserver(context, mHandler);
270     }
271 
onCreate()272     public void onCreate() {
273         if (VDBG) Log.v(LOG_TAG, "onCreate()...");
274 
275         ContentResolver resolver = getContentResolver();
276 
277         // Cache the "voice capable" flag.
278         // This flag currently comes from a resource (which is
279         // overrideable on a per-product basis):
280         sVoiceCapable =
281                 getResources().getBoolean(com.android.internal.R.bool.config_voice_capable);
282         // ...but this might eventually become a PackageManager "system
283         // feature" instead, in which case we'd do something like:
284         // sVoiceCapable =
285         //   getPackageManager().hasSystemFeature(PackageManager.FEATURE_TELEPHONY_VOICE_CALLS);
286 
287         if (mCM == null) {
288             // Initialize AnomalyReporter early so that it can be used
289             AnomalyReporter.initialize(this);
290 
291             // Inject telephony component factory if configured using other jars.
292             XmlResourceParser parser = getResources().getXml(R.xml.telephony_injection);
293             TelephonyComponentFactory.getInstance().injectTheComponentFactory(parser);
294             // Initialize the telephony framework
295             PhoneFactory.makeDefaultPhones(this);
296 
297             // Start TelephonyDebugService After the default phone is created.
298             Intent intent = new Intent(this, TelephonyDebugService.class);
299             startService(intent);
300 
301             mCM = CallManager.getInstance();
302             for (Phone phone : PhoneFactory.getPhones()) {
303                 mCM.registerPhone(phone);
304             }
305 
306             // Create the NotificationMgr singleton, which is used to display
307             // status bar icons and control other status bar behavior.
308             notificationMgr = NotificationMgr.init(this);
309 
310             // If PhoneGlobals has crashed and is being restarted, then restart.
311             mHandler.sendEmptyMessage(EVENT_RESTART_SIP);
312 
313             // Create an instance of CdmaPhoneCallState and initialize it to IDLE
314             cdmaPhoneCallState = new CdmaPhoneCallState();
315             cdmaPhoneCallState.CdmaPhoneCallStateInit();
316 
317             // before registering for phone state changes
318             mPowerManager = (PowerManager) getSystemService(Context.POWER_SERVICE);
319             mWakeLock = mPowerManager.newWakeLock(PowerManager.FULL_WAKE_LOCK, LOG_TAG);
320             // lock used to keep the processor awake, when we don't care for the display.
321             mPartialWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK
322                     | PowerManager.ON_AFTER_RELEASE, LOG_TAG);
323 
324             mKeyguardManager = (KeyguardManager) getSystemService(Context.KEYGUARD_SERVICE);
325 
326             // Get UpdateLock to suppress system-update related events (e.g. dialog show-up)
327             // during phone calls.
328             mUpdateLock = new UpdateLock("phone");
329 
330             if (DBG) Log.d(LOG_TAG, "onCreate: mUpdateLock: " + mUpdateLock);
331 
332             // Create the CallerInfoCache singleton, which remembers custom ring tone and
333             // send-to-voicemail settings.
334             //
335             // The asynchronous caching will start just after this call.
336             callerInfoCache = CallerInfoCache.init(this);
337 
338             phoneMgr = PhoneInterfaceManager.init(this);
339 
340             configLoader = CarrierConfigLoader.init(this);
341 
342             // Create the CallNotifier singleton, which handles
343             // asynchronous events from the telephony layer (like
344             // launching the incoming-call UI when an incoming call comes
345             // in.)
346             notifier = CallNotifier.init(this);
347 
348             PhoneUtils.registerIccStatus(mHandler, EVENT_SIM_NETWORK_LOCKED);
349 
350             // register for MMI/USSD
351             mCM.registerForMmiComplete(mHandler, MMI_COMPLETE, null);
352 
353             // Register for misc other intent broadcasts.
354             IntentFilter intentFilter =
355                     new IntentFilter(Intent.ACTION_AIRPLANE_MODE_CHANGED);
356             intentFilter.addAction(TelephonyIntents.ACTION_SIM_STATE_CHANGED);
357             intentFilter.addAction(TelephonyIntents.ACTION_RADIO_TECHNOLOGY_CHANGED);
358             intentFilter.addAction(TelephonyIntents.ACTION_SERVICE_STATE_CHANGED);
359             intentFilter.addAction(TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED);
360             intentFilter.addAction(TelephonyIntents.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED);
361             intentFilter.addAction(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED);
362             registerReceiver(mReceiver, intentFilter);
363 
364             IntentFilter sipIntentFilter = new IntentFilter(Intent.ACTION_BOOT_COMPLETED);
365             sipIntentFilter.addAction(SipManager.ACTION_SIP_SERVICE_UP);
366             sipIntentFilter.addAction(SipManager.ACTION_SIP_CALL_OPTION_CHANGED);
367             sipIntentFilter.addAction(SipManager.ACTION_SIP_REMOVE_PHONE);
368             registerReceiver(mSipReceiver, sipIntentFilter);
369 
370             mCarrierVvmPackageInstalledReceiver.register(this);
371 
372             //set the default values for the preferences in the phone.
373             PreferenceManager.setDefaultValues(this, R.xml.network_setting_fragment, false);
374 
375             PreferenceManager.setDefaultValues(this, R.xml.call_feature_setting, false);
376         }
377 
378         // XXX pre-load the SimProvider so that it's ready
379         resolver.getType(Uri.parse("content://icc/adn"));
380 
381         // TODO: Register for Cdma Information Records
382         // phone.registerCdmaInformationRecord(mHandler, EVENT_UNSOL_CDMA_INFO_RECORD, null);
383 
384         // Read HAC settings and configure audio hardware
385         if (getResources().getBoolean(R.bool.hac_enabled)) {
386             int hac = android.provider.Settings.System.getInt(
387                     getContentResolver(),
388                     android.provider.Settings.System.HEARING_AID,
389                     0);
390             AudioManager audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
391             audioManager.setParameter(SettingsConstants.HAC_KEY,
392                     hac == SettingsConstants.HAC_ENABLED
393                             ? SettingsConstants.HAC_VAL_ON : SettingsConstants.HAC_VAL_OFF);
394         }
395     }
396 
397     /**
398      * Returns the singleton instance of the PhoneApp.
399      */
getInstance()400     public static PhoneGlobals getInstance() {
401         if (sMe == null) {
402             throw new IllegalStateException("No PhoneGlobals here!");
403         }
404         return sMe;
405     }
406 
407     /**
408      * Returns the default phone.
409      *
410      * WARNING: This method should be used carefully, now that there may be multiple phones.
411      */
getPhone()412     public static Phone getPhone() {
413         return PhoneFactory.getDefaultPhone();
414     }
415 
getPhone(int subId)416     public static Phone getPhone(int subId) {
417         return PhoneFactory.getPhone(SubscriptionManager.getPhoneId(subId));
418     }
419 
getCallManager()420     /* package */ CallManager getCallManager() {
421         return mCM;
422     }
423 
getCarrierConfig()424     public PersistableBundle getCarrierConfig() {
425         return getCarrierConfigForSubId(SubscriptionManager.getDefaultSubscriptionId());
426     }
427 
getCarrierConfigForSubId(int subId)428     public PersistableBundle getCarrierConfigForSubId(int subId) {
429         return configLoader.getConfigForSubId(subId, getOpPackageName());
430     }
431 
registerSettingsObserver()432     private void registerSettingsObserver() {
433         mSettingsObserver.unobserve();
434         String dataRoamingSetting = Settings.Global.DATA_ROAMING;
435         String mobileDataSetting = Settings.Global.MOBILE_DATA;
436         if (TelephonyManager.getDefault().getSimCount() > 1) {
437             int subId = mDefaultDataSubId;
438             if (subId != SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
439                 dataRoamingSetting += subId;
440                 mobileDataSetting += subId;
441             }
442         }
443 
444         // Listen for user data roaming setting changed event
445         mSettingsObserver.observe(Settings.Global.getUriFor(dataRoamingSetting),
446                 EVENT_DATA_ROAMING_SETTINGS_CHANGED);
447 
448         // Listen for mobile data setting changed event
449         mSettingsObserver.observe(Settings.Global.getUriFor(mobileDataSetting),
450                 EVENT_MOBILE_DATA_SETTINGS_CHANGED);
451     }
452 
453     /**
454      * Sets the activity responsible for un-PUK-blocking the device
455      * so that we may close it when we receive a positive result.
456      * mPUKEntryActivity is also used to indicate to the device that
457      * we are trying to un-PUK-lock the phone. In other words, iff
458      * it is NOT null, then we are trying to unlock and waiting for
459      * the SIM to move to READY state.
460      *
461      * @param activity is the activity to close when PUK has
462      * finished unlocking. Can be set to null to indicate the unlock
463      * or SIM READYing process is over.
464      */
setPukEntryActivity(Activity activity)465     void setPukEntryActivity(Activity activity) {
466         mPUKEntryActivity = activity;
467     }
468 
getPUKEntryActivity()469     Activity getPUKEntryActivity() {
470         return mPUKEntryActivity;
471     }
472 
473     /**
474      * Sets the dialog responsible for notifying the user of un-PUK-
475      * blocking - SIM READYing progress, so that we may dismiss it
476      * when we receive a positive result.
477      *
478      * @param dialog indicates the progress dialog informing the user
479      * of the state of the device.  Dismissed upon completion of
480      * READYing process
481      */
setPukEntryProgressDialog(ProgressDialog dialog)482     void setPukEntryProgressDialog(ProgressDialog dialog) {
483         mPUKEntryProgressDialog = dialog;
484     }
485 
486     /**
487      * If we are not currently keeping the screen on, then poke the power
488      * manager to wake up the screen for the user activity timeout duration.
489      */
wakeUpScreen()490     /* package */ void wakeUpScreen() {
491         synchronized (this) {
492             if (mWakeState == WakeState.SLEEP) {
493                 if (DBG) Log.d(LOG_TAG, "pulse screen lock");
494                 mPowerManager.wakeUp(SystemClock.uptimeMillis(), "android.phone:WAKE");
495             }
496         }
497     }
498 
getKeyguardManager()499     KeyguardManager getKeyguardManager() {
500         return mKeyguardManager;
501     }
502 
onMMIComplete(AsyncResult r)503     private void onMMIComplete(AsyncResult r) {
504         if (VDBG) Log.d(LOG_TAG, "onMMIComplete()...");
505         MmiCode mmiCode = (MmiCode) r.result;
506         PhoneUtils.displayMMIComplete(mmiCode.getPhone(), getInstance(), mmiCode, null, null);
507     }
508 
initForNewRadioTechnology()509     private void initForNewRadioTechnology() {
510         if (DBG) Log.d(LOG_TAG, "initForNewRadioTechnology...");
511         notifier.updateCallNotifierRegistrationsAfterRadioTechnologyChange();
512     }
513 
handleAirplaneModeChange(Context context, int newMode)514     private void handleAirplaneModeChange(Context context, int newMode) {
515         int cellState = Settings.Global.getInt(context.getContentResolver(),
516                 Settings.Global.CELL_ON, PhoneConstants.CELL_ON_FLAG);
517         boolean isAirplaneNewlyOn = (newMode == 1);
518         switch (cellState) {
519             case PhoneConstants.CELL_OFF_FLAG:
520                 // Airplane mode does not affect the cell radio if user
521                 // has turned it off.
522                 break;
523             case PhoneConstants.CELL_ON_FLAG:
524                 maybeTurnCellOff(context, isAirplaneNewlyOn);
525                 break;
526             case PhoneConstants.CELL_OFF_DUE_TO_AIRPLANE_MODE_FLAG:
527                 maybeTurnCellOn(context, isAirplaneNewlyOn);
528                 break;
529         }
530     }
531 
532     /*
533      * Returns true if the radio must be turned off when entering airplane mode.
534      */
isCellOffInAirplaneMode(Context context)535     private boolean isCellOffInAirplaneMode(Context context) {
536         String airplaneModeRadios = Settings.Global.getString(context.getContentResolver(),
537                 Settings.Global.AIRPLANE_MODE_RADIOS);
538         return airplaneModeRadios == null
539                 || airplaneModeRadios.contains(Settings.Global.RADIO_CELL);
540     }
541 
setRadioPowerOff(Context context)542     private void setRadioPowerOff(Context context) {
543         Log.i(LOG_TAG, "Turning radio off - airplane");
544         Settings.Global.putInt(context.getContentResolver(), Settings.Global.CELL_ON,
545                  PhoneConstants.CELL_OFF_DUE_TO_AIRPLANE_MODE_FLAG);
546         SystemProperties.set("persist.radio.airplane_mode_on", "1");
547         Settings.Global.putInt(getContentResolver(), Settings.Global.ENABLE_CELLULAR_ON_BOOT, 0);
548         PhoneUtils.setRadioPower(false);
549     }
550 
setRadioPowerOn(Context context)551     private void setRadioPowerOn(Context context) {
552         Log.i(LOG_TAG, "Turning radio on - airplane");
553         Settings.Global.putInt(context.getContentResolver(), Settings.Global.CELL_ON,
554                 PhoneConstants.CELL_ON_FLAG);
555         Settings.Global.putInt(getContentResolver(), Settings.Global.ENABLE_CELLULAR_ON_BOOT,
556                 1);
557         SystemProperties.set("persist.radio.airplane_mode_on", "0");
558         PhoneUtils.setRadioPower(true);
559     }
560 
maybeTurnCellOff(Context context, boolean isAirplaneNewlyOn)561     private void maybeTurnCellOff(Context context, boolean isAirplaneNewlyOn) {
562         if (isAirplaneNewlyOn) {
563             // If we are trying to turn off the radio, make sure there are no active
564             // emergency calls.  If there are, switch airplane mode back to off.
565             TelecomManager tm = (TelecomManager) context.getSystemService(TELECOM_SERVICE);
566 
567             if (tm != null && tm.isInEmergencyCall()) {
568                 // Switch airplane mode back to off.
569                 ConnectivityManager.from(this).setAirplaneMode(false);
570                 Toast.makeText(this, R.string.radio_off_during_emergency_call, Toast.LENGTH_LONG)
571                         .show();
572                 Log.i(LOG_TAG, "Ignoring airplane mode: emergency call. Turning airplane off");
573             } else if (isCellOffInAirplaneMode(context)) {
574                 setRadioPowerOff(context);
575             } else {
576                 Log.i(LOG_TAG, "Ignoring airplane mode: settings prevent cell radio power off");
577             }
578         }
579     }
580 
maybeTurnCellOn(Context context, boolean isAirplaneNewlyOn)581     private void maybeTurnCellOn(Context context, boolean isAirplaneNewlyOn) {
582         if (!isAirplaneNewlyOn) {
583             setRadioPowerOn(context);
584         }
585     }
586 
587     /**
588      * Receiver for misc intent broadcasts the Phone app cares about.
589      */
590     private class PhoneAppBroadcastReceiver extends BroadcastReceiver {
591         @Override
onReceive(Context context, Intent intent)592         public void onReceive(Context context, Intent intent) {
593             String action = intent.getAction();
594             if (action.equals(Intent.ACTION_AIRPLANE_MODE_CHANGED)) {
595                 int airplaneMode = Settings.Global.getInt(getContentResolver(),
596                         Settings.Global.AIRPLANE_MODE_ON, AIRPLANE_OFF);
597                 // Treat any non-OFF values as ON.
598                 if (airplaneMode != AIRPLANE_OFF) {
599                     airplaneMode = AIRPLANE_ON;
600                 }
601                 handleAirplaneModeChange(context, airplaneMode);
602             } else if (action.equals(TelephonyIntents.ACTION_SIM_STATE_CHANGED)) {
603                 // re-register as it may be a new IccCard
604                 int phoneId = intent.getIntExtra(PhoneConstants.PHONE_KEY,
605                         SubscriptionManager.INVALID_PHONE_INDEX);
606                 if (SubscriptionManager.isValidPhoneId(phoneId)) {
607                     PhoneUtils.unregisterIccStatus(mHandler, phoneId);
608                     PhoneUtils.registerIccStatus(mHandler, EVENT_SIM_NETWORK_LOCKED, phoneId);
609                 }
610                 if (mPUKEntryActivity != null) {
611                     // if an attempt to un-PUK-lock the device was made, while we're
612                     // receiving this state change notification, notify the handler.
613                     // NOTE: This is ONLY triggered if an attempt to un-PUK-lock has
614                     // been attempted.
615                     mHandler.sendMessage(mHandler.obtainMessage(EVENT_SIM_STATE_CHANGED,
616                             intent.getStringExtra(IccCardConstants.INTENT_KEY_ICC_STATE)));
617                 }
618             } else if (action.equals(TelephonyIntents.ACTION_RADIO_TECHNOLOGY_CHANGED)) {
619                 String newPhone = intent.getStringExtra(PhoneConstants.PHONE_NAME_KEY);
620                 Log.d(LOG_TAG, "Radio technology switched. Now " + newPhone + " is active.");
621                 initForNewRadioTechnology();
622             } else if (action.equals(TelephonyIntents.ACTION_SERVICE_STATE_CHANGED)) {
623                 handleServiceStateChanged(intent);
624             } else if (action.equals(TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED)) {
625                 int phoneId = intent.getIntExtra(PhoneConstants.PHONE_KEY, 0);
626                 phoneInEcm = PhoneFactory.getPhone(phoneId);
627                 Log.d(LOG_TAG, "Emergency Callback Mode. phoneId:" + phoneId);
628                 if (phoneInEcm != null) {
629                     if (TelephonyCapabilities.supportsEcm(phoneInEcm)) {
630                         Log.d(LOG_TAG, "Emergency Callback Mode arrived in PhoneApp.");
631                         // Start Emergency Callback Mode service
632                         if (intent.getBooleanExtra("phoneinECMState", false)) {
633                             context.startService(new Intent(context,
634                                     EmergencyCallbackModeService.class));
635                         } else {
636                             phoneInEcm = null;
637                         }
638                     } else {
639                         // It doesn't make sense to get ACTION_EMERGENCY_CALLBACK_MODE_CHANGED
640                         // on a device that doesn't support ECM in the first place.
641                         Log.e(LOG_TAG, "Got ACTION_EMERGENCY_CALLBACK_MODE_CHANGED, but "
642                                 + "ECM isn't supported for phone: " + phoneInEcm.getPhoneName());
643                         phoneInEcm = null;
644                     }
645                 } else {
646                     Log.w(LOG_TAG, "phoneInEcm is null.");
647                 }
648             } else if (action.equals(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED)) {
649                 // Roaming status could be overridden by carrier config, so we need to update it.
650                 if (VDBG) Log.v(LOG_TAG, "carrier config changed.");
651                 updateDataRoamingStatus();
652             } else if (action.equals(TelephonyIntents.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED)) {
653                 // We also need to pay attention when default data subscription changes.
654                 if (VDBG) Log.v(LOG_TAG, "default data sub changed.");
655                 mDefaultDataSubId = SubscriptionManager.getDefaultDataSubscriptionId();
656                 registerSettingsObserver();
657                 Phone phone = getPhone(mDefaultDataSubId);
658                 if (phone != null) {
659                     updateDataRoamingStatus();
660                 }
661             }
662         }
663     }
664 
665     private class SipReceiver extends BroadcastReceiver {
666 
667         @Override
onReceive(Context context, Intent intent)668         public void onReceive(Context context, Intent intent) {
669             String action = intent.getAction();
670 
671             SipAccountRegistry sipAccountRegistry = SipAccountRegistry.getInstance();
672             if (action.equals(Intent.ACTION_BOOT_COMPLETED)) {
673                 SipUtil.startSipService();
674             } else if (action.equals(SipManager.ACTION_SIP_SERVICE_UP)
675                     || action.equals(SipManager.ACTION_SIP_CALL_OPTION_CHANGED)) {
676                 sipAccountRegistry.setup(context);
677             } else if (action.equals(SipManager.ACTION_SIP_REMOVE_PHONE)) {
678                 if (DBG) {
679                     Log.d(LOG_TAG, "SIP_REMOVE_PHONE "
680                             + intent.getStringExtra(SipManager.EXTRA_LOCAL_URI));
681                 }
682                 sipAccountRegistry.removeSipProfile(intent.getStringExtra(
683                         SipManager.EXTRA_LOCAL_URI));
684             } else {
685                 if (DBG) Log.d(LOG_TAG, "onReceive, action not processed: " + action);
686             }
687         }
688     }
689 
handleServiceStateChanged(Intent intent)690     private void handleServiceStateChanged(Intent intent) {
691         /**
692          * This used to handle updating EriTextWidgetProvider this routine
693          * and and listening for ACTION_SERVICE_STATE_CHANGED intents could
694          * be removed. But leaving just in case it might be needed in the near
695          * future.
696          */
697 
698         if (VDBG) Log.v(LOG_TAG, "handleServiceStateChanged");
699         // If service just returned, start sending out the queued messages
700         Bundle extras = intent.getExtras();
701         if (extras != null) {
702             ServiceState ss = ServiceState.newFromBundle(extras);
703             if (ss != null) {
704                 int state = ss.getState();
705                 int subId = intent.getIntExtra(PhoneConstants.SUBSCRIPTION_KEY,
706                         SubscriptionManager.INVALID_SUBSCRIPTION_ID);
707                 notificationMgr.updateNetworkSelection(state, subId);
708 
709                 if (VDBG) {
710                     Log.v(LOG_TAG, "subId=" + subId + ",mDefaultDataSubId="
711                             + mDefaultDataSubId + ",ss roaming=" + ss.getDataRoaming());
712                 }
713                 if (subId == mDefaultDataSubId) {
714                     updateDataRoamingStatus();
715                 }
716             }
717         }
718     }
719 
720     /**
721      * When roaming, if mobile data cannot be established due to data roaming not enabled, we need
722      * to notify the user so they can enable it through settings. Vise versa if the condition
723      * changes, we need to dismiss the notification.
724      */
updateDataRoamingStatus()725     private void updateDataRoamingStatus() {
726         if (VDBG) Log.v(LOG_TAG, "updateDataRoamingStatus");
727         Phone phone = getPhone(mDefaultDataSubId);
728         if (phone == null) {
729             Log.w(LOG_TAG, "Can't get phone with sub id = " + mDefaultDataSubId);
730             return;
731         }
732 
733         DataConnectionReasons reasons = new DataConnectionReasons();
734         boolean dataAllowed = phone.isDataAllowed(ApnSetting.TYPE_DEFAULT, reasons);
735         mDataRoamingNotifLog.log("dataAllowed=" + dataAllowed + ", reasons=" + reasons);
736         if (VDBG) Log.v(LOG_TAG, "dataAllowed=" + dataAllowed + ", reasons=" + reasons);
737         if (!mNoDataDueToRoaming
738                 && !dataAllowed
739                 && reasons.containsOnly(DataDisallowedReasonType.ROAMING_DISABLED)) {
740             // If the only reason of no data is data roaming disabled, then we notify the user
741             // so the user can turn on data roaming.
742             mNoDataDueToRoaming = true;
743             Log.d(LOG_TAG, "Show roaming disconnected notification");
744             mDataRoamingNotifLog.log("Show");
745             Message msg = mHandler.obtainMessage(EVENT_DATA_ROAMING_DISCONNECTED);
746             msg.arg1 = mDefaultDataSubId;
747             msg.sendToTarget();
748         } else if (mNoDataDueToRoaming && (dataAllowed
749                 || !reasons.containsOnly(DataDisallowedReasonType.ROAMING_DISABLED))) {
750             // Otherwise dismiss the notification we showed earlier.
751             mNoDataDueToRoaming = false;
752             Log.d(LOG_TAG, "Dismiss roaming disconnected notification");
753             mDataRoamingNotifLog.log("Hide. data allowed=" + dataAllowed + ", reasons=" + reasons);
754             mHandler.sendEmptyMessage(EVENT_DATA_ROAMING_OK);
755         }
756     }
757 
getPhoneInEcm()758     public Phone getPhoneInEcm() {
759         return phoneInEcm;
760     }
761 
762     /**
763      * Triggers a refresh of the message waiting (voicemail) indicator.
764      *
765      * @param subId the subscription id we should refresh the notification for.
766      */
refreshMwiIndicator(int subId)767     public void refreshMwiIndicator(int subId) {
768         notificationMgr.refreshMwi(subId);
769     }
770 
771     /**
772      * Called when the network selection on the subscription {@code subId} is changed by the user.
773      *
774      * @param subId the subscription id.
775      */
onNetworkSelectionChanged(int subId)776     public void onNetworkSelectionChanged(int subId) {
777         Phone phone = getPhone(subId);
778         if (phone != null) {
779             notificationMgr.updateNetworkSelection(phone.getServiceState().getState(), subId);
780         } else {
781             Log.w(LOG_TAG, "onNetworkSelectionChanged on null phone, subId: " + subId);
782         }
783     }
784 
785     /**
786      * Dump the state of the object, add calls to other objects as desired.
787      *
788      * @param fd File descriptor
789      * @param printWriter Print writer
790      * @param args Arguments
791      */
dump(FileDescriptor fd, PrintWriter printWriter, String[] args)792     public void dump(FileDescriptor fd, PrintWriter printWriter, String[] args) {
793         IndentingPrintWriter pw = new IndentingPrintWriter(printWriter, "  ");
794         pw.println("------- PhoneGlobals -------");
795         pw.increaseIndent();
796         pw.println("mNoDataDueToRoaming=" + mNoDataDueToRoaming);
797         pw.println("mDefaultDataSubId=" + mDefaultDataSubId);
798         pw.println("mDataRoamingNotifLog:");
799         pw.println("isSmsCapable=" + TelephonyManager.from(this).isSmsCapable());
800         pw.increaseIndent();
801         mDataRoamingNotifLog.dump(fd, pw, args);
802         pw.decreaseIndent();
803         pw.decreaseIndent();
804         pw.println("------- End PhoneGlobals -------");
805     }
806 }
807