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