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