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