blob: 68239278173d6f8323f41ba9e8acdffecca175a7 [file] [log] [blame]
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001/*
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
17package com.android.phone;
18
19import android.app.Activity;
20import android.app.KeyguardManager;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070021import android.app.ProgressDialog;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070022import android.content.BroadcastReceiver;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070023import android.content.ContentResolver;
24import android.content.Context;
25import android.content.ContextWrapper;
26import android.content.Intent;
27import android.content.IntentFilter;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070028import android.media.AudioManager;
Santos Cordone18902f2016-03-22 17:16:04 -070029import android.net.ConnectivityManager;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070030import android.net.Uri;
31import android.os.AsyncResult;
Junda Liu605148f2015-04-28 15:23:40 -070032import android.os.Bundle;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070033import android.os.Handler;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070034import android.os.Message;
Jonathan Basseric31f1f32015-05-12 10:13:03 -070035import android.os.PersistableBundle;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070036import android.os.PowerManager;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070037import android.os.SystemClock;
38import android.os.SystemProperties;
39import android.os.UpdateLock;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070040import android.preference.PreferenceManager;
Sanket Padawe4c699232016-02-09 11:07:22 -080041import android.provider.Settings;
Junda Liu12f7d802015-05-01 12:06:44 -070042import android.telephony.CarrierConfigManager;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070043import android.telephony.ServiceState;
Andrew Lee385019f2014-11-24 14:19:50 -080044import android.telephony.SubscriptionManager;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070045import android.util.Log;
Santos Cordone18902f2016-03-22 17:16:04 -070046import android.widget.Toast;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070047
48import com.android.internal.telephony.Call;
49import com.android.internal.telephony.CallManager;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070050import com.android.internal.telephony.IccCardConstants;
51import com.android.internal.telephony.MmiCode;
52import com.android.internal.telephony.Phone;
53import com.android.internal.telephony.PhoneConstants;
54import com.android.internal.telephony.PhoneFactory;
55import com.android.internal.telephony.TelephonyCapabilities;
56import com.android.internal.telephony.TelephonyIntents;
Santos Cordon352ff652014-05-30 01:41:45 -070057import com.android.phone.common.CallLogAsync;
Andrew Leefb7f92e2015-02-26 16:23:32 -080058import com.android.phone.settings.SettingsConstants;
Santos Cordon76aaf482015-04-08 10:58:27 -070059import com.android.services.telephony.activation.SimActivationManager;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070060
61/**
62 * Global state for the telephony subsystem when running in the primary
63 * phone process.
64 */
Sailesh Nepalbf900542014-07-15 16:18:32 -070065public class PhoneGlobals extends ContextWrapper {
Andrew Lee83383e42014-10-31 12:42:28 -070066 public static final String LOG_TAG = "PhoneApp";
Santos Cordon7d4ddf62013-07-10 11:58:08 -070067
68 /**
69 * Phone app-wide debug level:
70 * 0 - no debug logging
71 * 1 - normal debug logging if ro.debuggable is set (which is true in
72 * "eng" and "userdebug" builds but not "user" builds)
73 * 2 - ultra-verbose debug logging
74 *
75 * Most individual classes in the phone app have a local DBG constant,
76 * typically set to
77 * (PhoneApp.DBG_LEVEL >= 1) && (SystemProperties.getInt("ro.debuggable", 0) == 1)
78 * or else
79 * (PhoneApp.DBG_LEVEL >= 2)
80 * depending on the desired verbosity.
81 *
82 * ***** DO NOT SUBMIT WITH DBG_LEVEL > 0 *************
83 */
Andrew Lee88b51e22014-10-29 15:48:51 -070084 public static final int DBG_LEVEL = 0;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070085
86 private static final boolean DBG =
87 (PhoneGlobals.DBG_LEVEL >= 1) && (SystemProperties.getInt("ro.debuggable", 0) == 1);
88 private static final boolean VDBG = (PhoneGlobals.DBG_LEVEL >= 2);
89
90 // Message codes; see mHandler below.
91 private static final int EVENT_SIM_NETWORK_LOCKED = 3;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070092 private static final int EVENT_SIM_STATE_CHANGED = 8;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070093 private static final int EVENT_DATA_ROAMING_DISCONNECTED = 10;
94 private static final int EVENT_DATA_ROAMING_OK = 11;
95 private static final int EVENT_UNSOL_CDMA_INFO_RECORD = 12;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070096
97 // The MMI codes are also used by the InCallScreen.
98 public static final int MMI_INITIATE = 51;
99 public static final int MMI_COMPLETE = 52;
100 public static final int MMI_CANCEL = 53;
101 // Don't use message codes larger than 99 here; those are reserved for
102 // the individual Activities of the Phone UI.
103
Santos Cordone18902f2016-03-22 17:16:04 -0700104 public static final int AIRPLANE_ON = 1;
105 public static final int AIRPLANE_OFF = 0;
106
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700107 /**
108 * Allowable values for the wake lock code.
109 * SLEEP means the device can be put to sleep.
110 * PARTIAL means wake the processor, but we display can be kept off.
111 * FULL means wake both the processor and the display.
112 */
113 public enum WakeState {
114 SLEEP,
115 PARTIAL,
116 FULL
117 }
118
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700119 private static PhoneGlobals sMe;
120
121 // A few important fields we expose to the rest of the package
122 // directly (rather than thru set/get methods) for efficiency.
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700123 CallController callController;
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700124 CallManager mCM;
Santos Cordon63a84242013-07-23 13:32:52 -0700125 CallNotifier notifier;
126 CallerInfoCache callerInfoCache;
Santos Cordon63a84242013-07-23 13:32:52 -0700127 NotificationMgr notificationMgr;
Andrew Lee9431b832015-03-09 18:46:45 -0700128 public PhoneInterfaceManager phoneMgr;
Santos Cordon76aaf482015-04-08 10:58:27 -0700129 public SimActivationManager simActivationManager;
Jonathan Basseri6465afd2015-02-25 13:05:57 -0800130 CarrierConfigLoader configLoader;
Santos Cordon63a84242013-07-23 13:32:52 -0700131
Santos Cordon69a69192013-08-22 14:25:42 -0700132 private CallGatewayManager callGatewayManager;
Sandeep Kuntade73a6a2014-10-15 18:45:56 +0530133 private Phone phoneInEcm;
Santos Cordon63a84242013-07-23 13:32:52 -0700134
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700135 static boolean sVoiceCapable = true;
136
Santos Cordonc593d002015-06-03 15:41:15 -0700137 // TODO: Remove, no longer used.
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700138 CdmaPhoneCallState cdmaPhoneCallState;
139
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700140 // The currently-active PUK entry activity and progress dialog.
141 // Normally, these are the Emergency Dialer and the subsequent
142 // progress dialog. null if there is are no such objects in
143 // the foreground.
144 private Activity mPUKEntryActivity;
145 private ProgressDialog mPUKEntryProgressDialog;
146
Yorke Lee4d2db1c2014-11-06 11:37:09 -0800147 private boolean mDataDisconnectedDueToRoaming = false;
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700148
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700149 private WakeState mWakeState = WakeState.SLEEP;
150
151 private PowerManager mPowerManager;
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700152 private PowerManager.WakeLock mWakeLock;
153 private PowerManager.WakeLock mPartialWakeLock;
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700154 private KeyguardManager mKeyguardManager;
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700155
156 private UpdateLock mUpdateLock;
157
158 // Broadcast receiver for various intent broadcasts (see onCreate())
159 private final BroadcastReceiver mReceiver = new PhoneAppBroadcastReceiver();
160
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700161 /**
162 * The singleton OtaUtils instance used for OTASP calls.
163 *
164 * The OtaUtils instance is created lazily the first time we need to
165 * make an OTASP call, regardless of whether it's an interactive or
166 * non-interactive OTASP call.
167 */
168 public OtaUtils otaUtils;
169
170 // Following are the CDMA OTA information Objects used during OTA Call.
171 // cdmaOtaProvisionData object store static OTA information that needs
172 // to be maintained even during Slider open/close scenarios.
173 // cdmaOtaConfigData object stores configuration info to control visiblity
174 // of each OTA Screens.
175 // cdmaOtaScreenState object store OTA Screen State information.
176 public OtaUtils.CdmaOtaProvisionData cdmaOtaProvisionData;
177 public OtaUtils.CdmaOtaConfigData cdmaOtaConfigData;
178 public OtaUtils.CdmaOtaScreenState cdmaOtaScreenState;
179 public OtaUtils.CdmaOtaInCallScreenUiState cdmaOtaInCallScreenUiState;
180
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700181 Handler mHandler = new Handler() {
182 @Override
183 public void handleMessage(Message msg) {
184 PhoneConstants.State phoneState;
185 switch (msg.what) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700186 // TODO: This event should be handled by the lock screen, just
187 // like the "SIM missing" and "Sim locked" cases (bug 1804111).
188 case EVENT_SIM_NETWORK_LOCKED:
Jonathan Basseri9504c6b2015-06-04 14:23:32 -0700189 if (getCarrierConfig().getBoolean(
190 CarrierConfigManager.KEY_IGNORE_SIM_NETWORK_LOCKED_EVENTS_BOOL)) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700191 // Some products don't have the concept of a "SIM network lock"
192 Log.i(LOG_TAG, "Ignoring EVENT_SIM_NETWORK_LOCKED event; "
193 + "not showing 'SIM network unlock' PIN entry screen");
194 } else {
195 // Normal case: show the "SIM network unlock" PIN entry screen.
196 // The user won't be able to do anything else until
197 // they enter a valid SIM network PIN.
198 Log.i(LOG_TAG, "show sim depersonal panel");
Tyler Gunn52a37072015-08-24 14:23:19 -0700199 IccNetworkDepersonalizationPanel.showDialog();
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700200 }
201 break;
202
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700203 case EVENT_DATA_ROAMING_DISCONNECTED:
204 notificationMgr.showDataDisconnectedRoaming();
205 break;
206
207 case EVENT_DATA_ROAMING_OK:
208 notificationMgr.hideDataDisconnectedRoaming();
209 break;
210
211 case MMI_COMPLETE:
212 onMMIComplete((AsyncResult) msg.obj);
213 break;
214
215 case MMI_CANCEL:
Stuart Scottdcf40a92014-12-09 10:45:01 -0800216 PhoneUtils.cancelMmiCode(mCM.getFgPhone());
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700217 break;
218
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700219 case EVENT_SIM_STATE_CHANGED:
220 // Marks the event where the SIM goes into ready state.
221 // Right now, this is only used for the PUK-unlocking
222 // process.
223 if (msg.obj.equals(IccCardConstants.INTENT_VALUE_ICC_READY)) {
224 // when the right event is triggered and there
225 // are UI objects in the foreground, we close
226 // them to display the lock panel.
227 if (mPUKEntryActivity != null) {
228 mPUKEntryActivity.finish();
229 mPUKEntryActivity = null;
230 }
231 if (mPUKEntryProgressDialog != null) {
232 mPUKEntryProgressDialog.dismiss();
233 mPUKEntryProgressDialog = null;
234 }
235 }
236 break;
237
238 case EVENT_UNSOL_CDMA_INFO_RECORD:
239 //TODO: handle message here;
240 break;
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700241 }
242 }
243 };
244
245 public PhoneGlobals(Context context) {
246 super(context);
247 sMe = this;
248 }
249
250 public void onCreate() {
251 if (VDBG) Log.v(LOG_TAG, "onCreate()...");
252
253 ContentResolver resolver = getContentResolver();
254
255 // Cache the "voice capable" flag.
256 // This flag currently comes from a resource (which is
257 // overrideable on a per-product basis):
258 sVoiceCapable =
259 getResources().getBoolean(com.android.internal.R.bool.config_voice_capable);
260 // ...but this might eventually become a PackageManager "system
261 // feature" instead, in which case we'd do something like:
262 // sVoiceCapable =
263 // getPackageManager().hasSystemFeature(PackageManager.FEATURE_TELEPHONY_VOICE_CALLS);
264
Stuart Scottdcf40a92014-12-09 10:45:01 -0800265 if (mCM == null) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700266 // Initialize the telephony framework
267 PhoneFactory.makeDefaultPhones(this);
268
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700269 // Start TelephonyDebugService After the default phone is created.
270 Intent intent = new Intent(this, TelephonyDebugService.class);
271 startService(intent);
272
273 mCM = CallManager.getInstance();
Stuart Scottdcf40a92014-12-09 10:45:01 -0800274 for (Phone phone : PhoneFactory.getPhones()) {
275 mCM.registerPhone(phone);
Stuart Scottdcf40a92014-12-09 10:45:01 -0800276 }
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700277
278 // Create the NotificationMgr singleton, which is used to display
279 // status bar icons and control other status bar behavior.
280 notificationMgr = NotificationMgr.init(this);
281
Anthony Lee03ebdfc2015-07-27 08:12:02 -0700282 // Create an instance of CdmaPhoneCallState and initialize it to IDLE
283 cdmaPhoneCallState = new CdmaPhoneCallState();
284 cdmaPhoneCallState.CdmaPhoneCallStateInit();
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700285
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700286 // before registering for phone state changes
287 mPowerManager = (PowerManager) getSystemService(Context.POWER_SERVICE);
288 mWakeLock = mPowerManager.newWakeLock(PowerManager.FULL_WAKE_LOCK, LOG_TAG);
289 // lock used to keep the processor awake, when we don't care for the display.
290 mPartialWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK
291 | PowerManager.ON_AFTER_RELEASE, LOG_TAG);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700292
293 mKeyguardManager = (KeyguardManager) getSystemService(Context.KEYGUARD_SERVICE);
294
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700295 // Get UpdateLock to suppress system-update related events (e.g. dialog show-up)
296 // during phone calls.
297 mUpdateLock = new UpdateLock("phone");
298
299 if (DBG) Log.d(LOG_TAG, "onCreate: mUpdateLock: " + mUpdateLock);
300
301 CallLogger callLogger = new CallLogger(this, new CallLogAsync());
302
Jay Shrauner21a75342013-11-25 16:14:43 -0800303 callGatewayManager = CallGatewayManager.getInstance();
Santos Cordon69a69192013-08-22 14:25:42 -0700304
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700305 // Create the CallController singleton, which is the interface
306 // to the telephony layer for user-initiated telephony functionality
307 // (like making outgoing calls.)
Santos Cordon69a69192013-08-22 14:25:42 -0700308 callController = CallController.init(this, callLogger, callGatewayManager);
309
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700310 // Create the CallerInfoCache singleton, which remembers custom ring tone and
311 // send-to-voicemail settings.
312 //
313 // The asynchronous caching will start just after this call.
314 callerInfoCache = CallerInfoCache.init(this);
315
Stuart Scottdcf40a92014-12-09 10:45:01 -0800316 phoneMgr = PhoneInterfaceManager.init(this, PhoneFactory.getDefaultPhone());
Santos Cordon406c0342013-08-28 00:07:47 -0700317
Jonathan Basseri6465afd2015-02-25 13:05:57 -0800318 configLoader = CarrierConfigLoader.init(this);
319
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700320 // Create the CallNotifer singleton, which handles
321 // asynchronous events from the telephony layer (like
322 // launching the incoming-call UI when an incoming call comes
323 // in.)
Brad Ebingera9c6b6d2016-01-07 17:24:16 -0800324 notifier = CallNotifier.init(this);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700325
Stuart Scottdcf40a92014-12-09 10:45:01 -0800326 PhoneUtils.registerIccStatus(mHandler, EVENT_SIM_NETWORK_LOCKED);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700327
328 // register for MMI/USSD
329 mCM.registerForMmiComplete(mHandler, MMI_COMPLETE, null);
330
331 // register connection tracking to PhoneUtils
332 PhoneUtils.initializeConnectionHandler(mCM);
333
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700334 // Register for misc other intent broadcasts.
335 IntentFilter intentFilter =
336 new IntentFilter(Intent.ACTION_AIRPLANE_MODE_CHANGED);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700337 intentFilter.addAction(TelephonyIntents.ACTION_ANY_DATA_CONNECTION_STATE_CHANGED);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700338 intentFilter.addAction(TelephonyIntents.ACTION_SIM_STATE_CHANGED);
339 intentFilter.addAction(TelephonyIntents.ACTION_RADIO_TECHNOLOGY_CHANGED);
340 intentFilter.addAction(TelephonyIntents.ACTION_SERVICE_STATE_CHANGED);
341 intentFilter.addAction(TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700342 registerReceiver(mReceiver, intentFilter);
343
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700344 //set the default values for the preferences in the phone.
345 PreferenceManager.setDefaultValues(this, R.xml.network_setting, false);
346
347 PreferenceManager.setDefaultValues(this, R.xml.call_feature_setting, false);
348
349 // Make sure the audio mode (along with some
350 // audio-mode-related state of our own) is initialized
351 // correctly, given the current state of the phone.
352 PhoneUtils.setAudioMode(mCM);
353 }
354
Santos Cordon52bc81b2014-10-07 19:55:12 -0700355 cdmaOtaProvisionData = new OtaUtils.CdmaOtaProvisionData();
356 cdmaOtaConfigData = new OtaUtils.CdmaOtaConfigData();
357 cdmaOtaScreenState = new OtaUtils.CdmaOtaScreenState();
358 cdmaOtaInCallScreenUiState = new OtaUtils.CdmaOtaInCallScreenUiState();
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700359
Santos Cordon76aaf482015-04-08 10:58:27 -0700360 simActivationManager = new SimActivationManager();
361
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700362 // XXX pre-load the SimProvider so that it's ready
363 resolver.getType(Uri.parse("content://icc/adn"));
364
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700365 // TODO: Register for Cdma Information Records
366 // phone.registerCdmaInformationRecord(mHandler, EVENT_UNSOL_CDMA_INFO_RECORD, null);
367
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700368 // Read HAC settings and configure audio hardware
369 if (getResources().getBoolean(R.bool.hac_enabled)) {
Stuart Scottdcf40a92014-12-09 10:45:01 -0800370 int hac = android.provider.Settings.System.getInt(
371 getContentResolver(),
372 android.provider.Settings.System.HEARING_AID,
373 0);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700374 AudioManager audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
Andrew Leefb7f92e2015-02-26 16:23:32 -0800375 audioManager.setParameter(SettingsConstants.HAC_KEY,
376 hac == SettingsConstants.HAC_ENABLED
377 ? SettingsConstants.HAC_VAL_ON : SettingsConstants.HAC_VAL_OFF);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700378 }
Santos Cordonff506f52013-11-21 19:13:19 -0800379 }
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700380
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700381 /**
382 * Returns the singleton instance of the PhoneApp.
383 */
Sailesh Nepal1eaf22b2014-02-22 17:00:49 -0800384 public static PhoneGlobals getInstance() {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700385 if (sMe == null) {
386 throw new IllegalStateException("No PhoneGlobals here!");
387 }
388 return sMe;
389 }
390
391 /**
392 * Returns the singleton instance of the PhoneApp if running as the
393 * primary user, otherwise null.
394 */
395 static PhoneGlobals getInstanceIfPrimary() {
396 return sMe;
397 }
398
399 /**
Stuart Scottdcf40a92014-12-09 10:45:01 -0800400 * Returns the default phone.
401 *
Andrew Lee385019f2014-11-24 14:19:50 -0800402 * WARNING: This method should be used carefully, now that there may be multiple phones.
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700403 */
Andrew Lee83383e42014-10-31 12:42:28 -0700404 public static Phone getPhone() {
Stuart Scottdcf40a92014-12-09 10:45:01 -0800405 return PhoneFactory.getDefaultPhone();
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700406 }
407
Andrew Lee2fcb6c32014-12-04 14:52:35 -0800408 public static Phone getPhone(int subId) {
409 return PhoneFactory.getPhone(SubscriptionManager.getPhoneId(subId));
Andrew Lee385019f2014-11-24 14:19:50 -0800410 }
411
Santos Cordonde10b752013-09-19 04:11:33 -0700412 /* package */ CallManager getCallManager() {
413 return mCM;
414 }
415
Chris Manton4e9fa912015-06-19 11:26:57 -0700416 public PersistableBundle getCarrierConfig() {
Shishir Agrawald3480e02016-01-25 13:05:49 -0800417 return getCarrierConfigForSubId(SubscriptionManager.getDefaultSubscriptionId());
Jonathan Basseri89b0ab42015-05-01 10:52:40 -0700418 }
419
Chris Manton4e9fa912015-06-19 11:26:57 -0700420 public PersistableBundle getCarrierConfigForSubId(int subId) {
Jonathan Basseri89b0ab42015-05-01 10:52:40 -0700421 return configLoader.getConfigForSubId(subId);
Junda Liu605148f2015-04-28 15:23:40 -0700422 }
423
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700424 /**
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700425 * Handles OTASP-related events from the telephony layer.
426 *
427 * While an OTASP call is active, the CallNotifier forwards
428 * OTASP-related telephony events to this method.
429 */
430 void handleOtaspEvent(Message msg) {
431 if (DBG) Log.d(LOG_TAG, "handleOtaspEvent(message " + msg + ")...");
432
433 if (otaUtils == null) {
434 // We shouldn't be getting OTASP events without ever
435 // having started the OTASP call in the first place!
436 Log.w(LOG_TAG, "handleOtaEvents: got an event but otaUtils is null! "
437 + "message = " + msg);
438 return;
439 }
440
441 otaUtils.onOtaProvisionStatusChanged((AsyncResult) msg.obj);
442 }
443
444 /**
445 * Similarly, handle the disconnect event of an OTASP call
446 * by forwarding it to the OtaUtils instance.
447 */
448 /* package */ void handleOtaspDisconnect() {
449 if (DBG) Log.d(LOG_TAG, "handleOtaspDisconnect()...");
450
451 if (otaUtils == null) {
452 // We shouldn't be getting OTASP events without ever
453 // having started the OTASP call in the first place!
454 Log.w(LOG_TAG, "handleOtaspDisconnect: otaUtils is null!");
455 return;
456 }
457
458 otaUtils.onOtaspDisconnect();
459 }
460
461 /**
462 * Sets the activity responsible for un-PUK-blocking the device
463 * so that we may close it when we receive a positive result.
464 * mPUKEntryActivity is also used to indicate to the device that
465 * we are trying to un-PUK-lock the phone. In other words, iff
466 * it is NOT null, then we are trying to unlock and waiting for
467 * the SIM to move to READY state.
468 *
469 * @param activity is the activity to close when PUK has
470 * finished unlocking. Can be set to null to indicate the unlock
471 * or SIM READYing process is over.
472 */
473 void setPukEntryActivity(Activity activity) {
474 mPUKEntryActivity = activity;
475 }
476
477 Activity getPUKEntryActivity() {
478 return mPUKEntryActivity;
479 }
480
481 /**
482 * Sets the dialog responsible for notifying the user of un-PUK-
483 * blocking - SIM READYing progress, so that we may dismiss it
484 * when we receive a positive result.
485 *
486 * @param dialog indicates the progress dialog informing the user
487 * of the state of the device. Dismissed upon completion of
488 * READYing process
489 */
490 void setPukEntryProgressDialog(ProgressDialog dialog) {
491 mPUKEntryProgressDialog = dialog;
492 }
493
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700494 /**
495 * Controls whether or not the screen is allowed to sleep.
496 *
497 * Once sleep is allowed (WakeState is SLEEP), it will rely on the
498 * settings for the poke lock to determine when to timeout and let
499 * the device sleep {@link PhoneGlobals#setScreenTimeout}.
500 *
501 * @param ws tells the device to how to wake.
502 */
503 /* package */ void requestWakeState(WakeState ws) {
504 if (VDBG) Log.d(LOG_TAG, "requestWakeState(" + ws + ")...");
505 synchronized (this) {
506 if (mWakeState != ws) {
507 switch (ws) {
508 case PARTIAL:
509 // acquire the processor wake lock, and release the FULL
510 // lock if it is being held.
511 mPartialWakeLock.acquire();
512 if (mWakeLock.isHeld()) {
513 mWakeLock.release();
514 }
515 break;
516 case FULL:
517 // acquire the full wake lock, and release the PARTIAL
518 // lock if it is being held.
519 mWakeLock.acquire();
520 if (mPartialWakeLock.isHeld()) {
521 mPartialWakeLock.release();
522 }
523 break;
524 case SLEEP:
525 default:
526 // release both the PARTIAL and FULL locks.
527 if (mWakeLock.isHeld()) {
528 mWakeLock.release();
529 }
530 if (mPartialWakeLock.isHeld()) {
531 mPartialWakeLock.release();
532 }
533 break;
534 }
535 mWakeState = ws;
536 }
537 }
538 }
539
540 /**
541 * If we are not currently keeping the screen on, then poke the power
542 * manager to wake up the screen for the user activity timeout duration.
543 */
544 /* package */ void wakeUpScreen() {
545 synchronized (this) {
546 if (mWakeState == WakeState.SLEEP) {
547 if (DBG) Log.d(LOG_TAG, "pulse screen lock");
Dianne Hackborn148769b2015-07-13 17:55:47 -0700548 mPowerManager.wakeUp(SystemClock.uptimeMillis(), "android.phone:WAKE");
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700549 }
550 }
551 }
552
553 /**
554 * Sets the wake state and screen timeout based on the current state
555 * of the phone, and the current state of the in-call UI.
556 *
557 * This method is a "UI Policy" wrapper around
558 * {@link PhoneGlobals#requestWakeState} and {@link PhoneGlobals#setScreenTimeout}.
559 *
560 * It's safe to call this method regardless of the state of the Phone
561 * (e.g. whether or not it's idle), and regardless of the state of the
562 * Phone UI (e.g. whether or not the InCallScreen is active.)
563 */
564 /* package */ void updateWakeState() {
565 PhoneConstants.State state = mCM.getState();
566
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700567 // True if the speakerphone is in use. (If so, we *always* use
568 // the default timeout. Since the user is obviously not holding
569 // the phone up to his/her face, we don't need to worry about
570 // false touches, and thus don't need to turn the screen off so
571 // aggressively.)
572 // Note that we need to make a fresh call to this method any
573 // time the speaker state changes. (That happens in
574 // PhoneUtils.turnOnSpeaker().)
575 boolean isSpeakerInUse = (state == PhoneConstants.State.OFFHOOK) && PhoneUtils.isSpeakerOn(this);
576
577 // TODO (bug 1440854): The screen timeout *might* also need to
578 // depend on the bluetooth state, but this isn't as clear-cut as
579 // the speaker state (since while using BT it's common for the
580 // user to put the phone straight into a pocket, in which case the
581 // timeout should probably still be short.)
582
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700583 // Decide whether to force the screen on or not.
584 //
585 // Force the screen to be on if the phone is ringing or dialing,
586 // or if we're displaying the "Call ended" UI for a connection in
587 // the "disconnected" state.
588 // However, if the phone is disconnected while the user is in the
589 // middle of selecting a quick response message, we should not force
590 // the screen to be on.
591 //
592 boolean isRinging = (state == PhoneConstants.State.RINGING);
Stuart Scottdcf40a92014-12-09 10:45:01 -0800593 boolean isDialing = (mCM.getFgPhone().getForegroundCall().getState() == Call.State.DIALING);
Jay Shrauner6fe8fd62013-09-16 19:39:30 -0700594 boolean keepScreenOn = isRinging || isDialing;
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700595 // keepScreenOn == true means we'll hold a full wake lock:
596 requestWakeState(keepScreenOn ? WakeState.FULL : WakeState.SLEEP);
597 }
598
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700599 KeyguardManager getKeyguardManager() {
600 return mKeyguardManager;
601 }
602
603 private void onMMIComplete(AsyncResult r) {
604 if (VDBG) Log.d(LOG_TAG, "onMMIComplete()...");
605 MmiCode mmiCode = (MmiCode) r.result;
Stuart Scottdcf40a92014-12-09 10:45:01 -0800606 PhoneUtils.displayMMIComplete(mmiCode.getPhone(), getInstance(), mmiCode, null, null);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700607 }
608
Stuart Scottdcf40a92014-12-09 10:45:01 -0800609 private void initForNewRadioTechnology(int phoneId) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700610 if (DBG) Log.d(LOG_TAG, "initForNewRadioTechnology...");
611
Stuart Scottdcf40a92014-12-09 10:45:01 -0800612 final Phone phone = PhoneFactory.getPhone(phoneId);
Santos Cordonc593d002015-06-03 15:41:15 -0700613 if (phone == null || !TelephonyCapabilities.supportsOtasp(phone)) {
614 // Clean up OTA for non-CDMA since it is only valid for CDMA.
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700615 clearOtaState();
616 }
617
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700618 notifier.updateCallNotifierRegistrationsAfterRadioTechnologyChange();
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700619 }
620
Santos Cordone18902f2016-03-22 17:16:04 -0700621 private void handleAirplaneModeChange(int newMode) {
622 if (newMode == AIRPLANE_ON) {
623 // If we are trying to turn off the radio, make sure there are no active
624 // emergency calls. If there are, switch airplane mode back to off.
625 if (PhoneUtils.isInEmergencyCall(mCM)) {
626 // Switch airplane mode back to off.
627 ConnectivityManager.from(this).setAirplaneMode(false);
628 Toast.makeText(this, R.string.radio_off_during_emergency_call, Toast.LENGTH_LONG)
629 .show();
630 Log.i(LOG_TAG, "Ignoring airplane mode: emergency call. Turning airplane off");
631 } else {
632 Log.i(LOG_TAG, "Turning radio off - airplane");
633 PhoneUtils.setRadioPower(false);
634 }
635 } else {
636 Log.i(LOG_TAG, "Turning radio on - airplane");
637 PhoneUtils.setRadioPower(true);
638 }
639 }
640
Santos Cordon593ab382013-08-06 21:58:23 -0700641 /**
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700642 * Receiver for misc intent broadcasts the Phone app cares about.
643 */
644 private class PhoneAppBroadcastReceiver extends BroadcastReceiver {
645 @Override
646 public void onReceive(Context context, Intent intent) {
647 String action = intent.getAction();
648 if (action.equals(Intent.ACTION_AIRPLANE_MODE_CHANGED)) {
Santos Cordone18902f2016-03-22 17:16:04 -0700649 int airplaneMode = Settings.Global.getInt(getContentResolver(),
650 Settings.Global.AIRPLANE_MODE_ON, AIRPLANE_OFF);
651 // Treat any non-OFF values as ON.
652 if (airplaneMode != AIRPLANE_OFF) {
653 airplaneMode = AIRPLANE_ON;
654 }
655 handleAirplaneModeChange(airplaneMode);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700656 } else if (action.equals(TelephonyIntents.ACTION_ANY_DATA_CONNECTION_STATE_CHANGED)) {
Stuart Scottdcf40a92014-12-09 10:45:01 -0800657 int subId = intent.getIntExtra(PhoneConstants.SUBSCRIPTION_KEY,
658 SubscriptionManager.INVALID_SUBSCRIPTION_ID);
659 int phoneId = SubscriptionManager.getPhoneId(subId);
660 String state = intent.getStringExtra(PhoneConstants.STATE_KEY);
661 if (VDBG) {
662 Log.d(LOG_TAG, "mReceiver: ACTION_ANY_DATA_CONNECTION_STATE_CHANGED");
663 Log.d(LOG_TAG, "- state: " + state);
664 Log.d(LOG_TAG, "- reason: "
665 + intent.getStringExtra(PhoneConstants.STATE_CHANGE_REASON_KEY));
666 Log.d(LOG_TAG, "- subId: " + subId);
667 Log.d(LOG_TAG, "- phoneId: " + phoneId);
668 }
669 Phone phone = SubscriptionManager.isValidPhoneId(phoneId) ?
670 PhoneFactory.getPhone(phoneId) : PhoneFactory.getDefaultPhone();
Santos Cordonc593d002015-06-03 15:41:15 -0700671
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700672 // The "data disconnected due to roaming" notification is shown
673 // if (a) you have the "data roaming" feature turned off, and
674 // (b) you just lost data connectivity because you're roaming.
675 boolean disconnectedDueToRoaming =
676 !phone.getDataRoamingEnabled()
Stuart Scottdcf40a92014-12-09 10:45:01 -0800677 && PhoneConstants.DataState.DISCONNECTED.equals(state)
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700678 && Phone.REASON_ROAMING_ON.equals(
679 intent.getStringExtra(PhoneConstants.STATE_CHANGE_REASON_KEY));
Yorke Lee4d2db1c2014-11-06 11:37:09 -0800680 if (mDataDisconnectedDueToRoaming != disconnectedDueToRoaming) {
681 mDataDisconnectedDueToRoaming = disconnectedDueToRoaming;
682 mHandler.sendEmptyMessage(disconnectedDueToRoaming
683 ? EVENT_DATA_ROAMING_DISCONNECTED : EVENT_DATA_ROAMING_OK);
684 }
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700685 } else if ((action.equals(TelephonyIntents.ACTION_SIM_STATE_CHANGED)) &&
686 (mPUKEntryActivity != null)) {
687 // if an attempt to un-PUK-lock the device was made, while we're
688 // receiving this state change notification, notify the handler.
689 // NOTE: This is ONLY triggered if an attempt to un-PUK-lock has
690 // been attempted.
691 mHandler.sendMessage(mHandler.obtainMessage(EVENT_SIM_STATE_CHANGED,
692 intent.getStringExtra(IccCardConstants.INTENT_KEY_ICC_STATE)));
693 } else if (action.equals(TelephonyIntents.ACTION_RADIO_TECHNOLOGY_CHANGED)) {
694 String newPhone = intent.getStringExtra(PhoneConstants.PHONE_NAME_KEY);
Stuart Scottdcf40a92014-12-09 10:45:01 -0800695 int phoneId = intent.getIntExtra(PhoneConstants.PHONE_KEY,
696 SubscriptionManager.INVALID_PHONE_INDEX);
697 Log.d(LOG_TAG, "Radio technology switched. Now " + newPhone + " (" + phoneId
698 + ") is active.");
699 initForNewRadioTechnology(phoneId);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700700 } else if (action.equals(TelephonyIntents.ACTION_SERVICE_STATE_CHANGED)) {
701 handleServiceStateChanged(intent);
702 } else if (action.equals(TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED)) {
Sandeep Kuntade73a6a2014-10-15 18:45:56 +0530703 int phoneId = intent.getIntExtra(PhoneConstants.PHONE_KEY, 0);
704 phoneInEcm = getPhone(phoneId);
705 Log.d(LOG_TAG, "Emergency Callback Mode. phoneId:" + phoneId);
706 if (phoneInEcm != null) {
707 if (TelephonyCapabilities.supportsEcm(phoneInEcm)) {
708 Log.d(LOG_TAG, "Emergency Callback Mode arrived in PhoneApp.");
709 // Start Emergency Callback Mode service
710 if (intent.getBooleanExtra("phoneinECMState", false)) {
711 context.startService(new Intent(context,
712 EmergencyCallbackModeService.class));
713 } else {
714 phoneInEcm = null;
715 }
716 } else {
717 // It doesn't make sense to get ACTION_EMERGENCY_CALLBACK_MODE_CHANGED
718 // on a device that doesn't support ECM in the first place.
719 Log.e(LOG_TAG, "Got ACTION_EMERGENCY_CALLBACK_MODE_CHANGED, but "
720 + "ECM isn't supported for phone: " + phoneInEcm.getPhoneName());
721 phoneInEcm = null;
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700722 }
723 } else {
Sandeep Kuntade73a6a2014-10-15 18:45:56 +0530724 Log.w(LOG_TAG, "phoneInEcm is null.");
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700725 }
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700726 }
727 }
728 }
729
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700730 private void handleServiceStateChanged(Intent intent) {
731 /**
732 * This used to handle updating EriTextWidgetProvider this routine
733 * and and listening for ACTION_SERVICE_STATE_CHANGED intents could
734 * be removed. But leaving just in case it might be needed in the near
735 * future.
736 */
737
738 // If service just returned, start sending out the queued messages
Santos Cordonc593d002015-06-03 15:41:15 -0700739 Bundle extras = intent.getExtras();
740 if (extras != null) {
741 ServiceState ss = ServiceState.newFromBundle(extras);
742 if (ss != null) {
743 int state = ss.getState();
744 notificationMgr.updateNetworkSelection(state);
745 }
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700746 }
747 }
748
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700749 // it is safe to call clearOtaState() even if the InCallScreen isn't active
750 public void clearOtaState() {
751 if (DBG) Log.d(LOG_TAG, "- clearOtaState ...");
Jay Shrauner6fe8fd62013-09-16 19:39:30 -0700752 if (otaUtils != null) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700753 otaUtils.cleanOtaScreen(true);
754 if (DBG) Log.d(LOG_TAG, " - clearOtaState clears OTA screen");
755 }
756 }
757
758 // it is safe to call dismissOtaDialogs() even if the InCallScreen isn't active
759 public void dismissOtaDialogs() {
760 if (DBG) Log.d(LOG_TAG, "- dismissOtaDialogs ...");
Jay Shrauner6fe8fd62013-09-16 19:39:30 -0700761 if (otaUtils != null) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700762 otaUtils.dismissAllOtaDialogs();
763 if (DBG) Log.d(LOG_TAG, " - dismissOtaDialogs clears OTA dialogs");
764 }
765 }
766
Sandeep Kuntade73a6a2014-10-15 18:45:56 +0530767 public Phone getPhoneInEcm() {
768 return phoneInEcm;
769 }
770
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700771 /**
Tyler Gunn9c1071f2014-12-09 10:07:54 -0800772 * Triggers a refresh of the message waiting (voicemail) indicator.
773 *
774 * @param subId the subscription id we should refresh the notification for.
775 */
776 public void refreshMwiIndicator(int subId) {
777 notificationMgr.refreshMwi(subId);
778 }
779
780 /**
Nancy Chenbb49d412015-07-23 13:54:16 -0700781 * Dismisses the message waiting (voicemail) indicator.
782 *
783 * @param subId the subscription id we should dismiss the notification for.
784 */
785 public void clearMwiIndicator(int subId) {
786 notificationMgr.updateMwi(subId, false);
787 }
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700788}