blob: e9f4c254bfe0c847d1a6ac8bba93a294a90e79c9 [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;
Santos Cordon63a84242013-07-23 13:32:52 -0700133
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700134 static boolean sVoiceCapable = true;
135
Santos Cordonc593d002015-06-03 15:41:15 -0700136 // TODO: Remove, no longer used.
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700137 CdmaPhoneCallState cdmaPhoneCallState;
138
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700139 // The currently-active PUK entry activity and progress dialog.
140 // Normally, these are the Emergency Dialer and the subsequent
141 // progress dialog. null if there is are no such objects in
142 // the foreground.
143 private Activity mPUKEntryActivity;
144 private ProgressDialog mPUKEntryProgressDialog;
145
Yorke Lee4d2db1c2014-11-06 11:37:09 -0800146 private boolean mDataDisconnectedDueToRoaming = false;
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700147
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700148 private WakeState mWakeState = WakeState.SLEEP;
149
150 private PowerManager mPowerManager;
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700151 private PowerManager.WakeLock mWakeLock;
152 private PowerManager.WakeLock mPartialWakeLock;
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700153 private KeyguardManager mKeyguardManager;
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700154
155 private UpdateLock mUpdateLock;
156
157 // Broadcast receiver for various intent broadcasts (see onCreate())
158 private final BroadcastReceiver mReceiver = new PhoneAppBroadcastReceiver();
159
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700160 /**
161 * The singleton OtaUtils instance used for OTASP calls.
162 *
163 * The OtaUtils instance is created lazily the first time we need to
164 * make an OTASP call, regardless of whether it's an interactive or
165 * non-interactive OTASP call.
166 */
167 public OtaUtils otaUtils;
168
169 // Following are the CDMA OTA information Objects used during OTA Call.
170 // cdmaOtaProvisionData object store static OTA information that needs
171 // to be maintained even during Slider open/close scenarios.
172 // cdmaOtaConfigData object stores configuration info to control visiblity
173 // of each OTA Screens.
174 // cdmaOtaScreenState object store OTA Screen State information.
175 public OtaUtils.CdmaOtaProvisionData cdmaOtaProvisionData;
176 public OtaUtils.CdmaOtaConfigData cdmaOtaConfigData;
177 public OtaUtils.CdmaOtaScreenState cdmaOtaScreenState;
178 public OtaUtils.CdmaOtaInCallScreenUiState cdmaOtaInCallScreenUiState;
179
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700180 Handler mHandler = new Handler() {
181 @Override
182 public void handleMessage(Message msg) {
183 PhoneConstants.State phoneState;
184 switch (msg.what) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700185 // TODO: This event should be handled by the lock screen, just
186 // like the "SIM missing" and "Sim locked" cases (bug 1804111).
187 case EVENT_SIM_NETWORK_LOCKED:
Jonathan Basseri9504c6b2015-06-04 14:23:32 -0700188 if (getCarrierConfig().getBoolean(
189 CarrierConfigManager.KEY_IGNORE_SIM_NETWORK_LOCKED_EVENTS_BOOL)) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700190 // Some products don't have the concept of a "SIM network lock"
191 Log.i(LOG_TAG, "Ignoring EVENT_SIM_NETWORK_LOCKED event; "
192 + "not showing 'SIM network unlock' PIN entry screen");
193 } else {
194 // Normal case: show the "SIM network unlock" PIN entry screen.
195 // The user won't be able to do anything else until
196 // they enter a valid SIM network PIN.
197 Log.i(LOG_TAG, "show sim depersonal panel");
Tyler Gunn52a37072015-08-24 14:23:19 -0700198 IccNetworkDepersonalizationPanel.showDialog();
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700199 }
200 break;
201
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700202 case EVENT_DATA_ROAMING_DISCONNECTED:
203 notificationMgr.showDataDisconnectedRoaming();
204 break;
205
206 case EVENT_DATA_ROAMING_OK:
207 notificationMgr.hideDataDisconnectedRoaming();
208 break;
209
210 case MMI_COMPLETE:
211 onMMIComplete((AsyncResult) msg.obj);
212 break;
213
214 case MMI_CANCEL:
Stuart Scottdcf40a92014-12-09 10:45:01 -0800215 PhoneUtils.cancelMmiCode(mCM.getFgPhone());
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700216 break;
217
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700218 case EVENT_SIM_STATE_CHANGED:
219 // Marks the event where the SIM goes into ready state.
220 // Right now, this is only used for the PUK-unlocking
221 // process.
222 if (msg.obj.equals(IccCardConstants.INTENT_VALUE_ICC_READY)) {
223 // when the right event is triggered and there
224 // are UI objects in the foreground, we close
225 // them to display the lock panel.
226 if (mPUKEntryActivity != null) {
227 mPUKEntryActivity.finish();
228 mPUKEntryActivity = null;
229 }
230 if (mPUKEntryProgressDialog != null) {
231 mPUKEntryProgressDialog.dismiss();
232 mPUKEntryProgressDialog = null;
233 }
234 }
235 break;
236
237 case EVENT_UNSOL_CDMA_INFO_RECORD:
238 //TODO: handle message here;
239 break;
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700240 }
241 }
242 };
243
244 public PhoneGlobals(Context context) {
245 super(context);
246 sMe = this;
247 }
248
249 public void onCreate() {
250 if (VDBG) Log.v(LOG_TAG, "onCreate()...");
251
252 ContentResolver resolver = getContentResolver();
253
254 // Cache the "voice capable" flag.
255 // This flag currently comes from a resource (which is
256 // overrideable on a per-product basis):
257 sVoiceCapable =
258 getResources().getBoolean(com.android.internal.R.bool.config_voice_capable);
259 // ...but this might eventually become a PackageManager "system
260 // feature" instead, in which case we'd do something like:
261 // sVoiceCapable =
262 // getPackageManager().hasSystemFeature(PackageManager.FEATURE_TELEPHONY_VOICE_CALLS);
263
Stuart Scottdcf40a92014-12-09 10:45:01 -0800264 if (mCM == null) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700265 // Initialize the telephony framework
266 PhoneFactory.makeDefaultPhones(this);
267
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700268 // Start TelephonyDebugService After the default phone is created.
269 Intent intent = new Intent(this, TelephonyDebugService.class);
270 startService(intent);
271
272 mCM = CallManager.getInstance();
Stuart Scottdcf40a92014-12-09 10:45:01 -0800273 for (Phone phone : PhoneFactory.getPhones()) {
274 mCM.registerPhone(phone);
Stuart Scottdcf40a92014-12-09 10:45:01 -0800275 }
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700276
277 // Create the NotificationMgr singleton, which is used to display
278 // status bar icons and control other status bar behavior.
279 notificationMgr = NotificationMgr.init(this);
280
Anthony Lee03ebdfc2015-07-27 08:12:02 -0700281 // Create an instance of CdmaPhoneCallState and initialize it to IDLE
282 cdmaPhoneCallState = new CdmaPhoneCallState();
283 cdmaPhoneCallState.CdmaPhoneCallStateInit();
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700284
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700285 // before registering for phone state changes
286 mPowerManager = (PowerManager) getSystemService(Context.POWER_SERVICE);
287 mWakeLock = mPowerManager.newWakeLock(PowerManager.FULL_WAKE_LOCK, LOG_TAG);
288 // lock used to keep the processor awake, when we don't care for the display.
289 mPartialWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK
290 | PowerManager.ON_AFTER_RELEASE, LOG_TAG);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700291
292 mKeyguardManager = (KeyguardManager) getSystemService(Context.KEYGUARD_SERVICE);
293
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700294 // Get UpdateLock to suppress system-update related events (e.g. dialog show-up)
295 // during phone calls.
296 mUpdateLock = new UpdateLock("phone");
297
298 if (DBG) Log.d(LOG_TAG, "onCreate: mUpdateLock: " + mUpdateLock);
299
300 CallLogger callLogger = new CallLogger(this, new CallLogAsync());
301
Jay Shrauner21a75342013-11-25 16:14:43 -0800302 callGatewayManager = CallGatewayManager.getInstance();
Santos Cordon69a69192013-08-22 14:25:42 -0700303
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700304 // Create the CallController singleton, which is the interface
305 // to the telephony layer for user-initiated telephony functionality
306 // (like making outgoing calls.)
Santos Cordon69a69192013-08-22 14:25:42 -0700307 callController = CallController.init(this, callLogger, callGatewayManager);
308
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700309 // Create the CallerInfoCache singleton, which remembers custom ring tone and
310 // send-to-voicemail settings.
311 //
312 // The asynchronous caching will start just after this call.
313 callerInfoCache = CallerInfoCache.init(this);
314
Stuart Scottdcf40a92014-12-09 10:45:01 -0800315 phoneMgr = PhoneInterfaceManager.init(this, PhoneFactory.getDefaultPhone());
Santos Cordon406c0342013-08-28 00:07:47 -0700316
Jonathan Basseri6465afd2015-02-25 13:05:57 -0800317 configLoader = CarrierConfigLoader.init(this);
318
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700319 // Create the CallNotifer singleton, which handles
320 // asynchronous events from the telephony layer (like
321 // launching the incoming-call UI when an incoming call comes
322 // in.)
Brad Ebingera9c6b6d2016-01-07 17:24:16 -0800323 notifier = CallNotifier.init(this);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700324
Stuart Scottdcf40a92014-12-09 10:45:01 -0800325 PhoneUtils.registerIccStatus(mHandler, EVENT_SIM_NETWORK_LOCKED);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700326
327 // register for MMI/USSD
328 mCM.registerForMmiComplete(mHandler, MMI_COMPLETE, null);
329
330 // register connection tracking to PhoneUtils
331 PhoneUtils.initializeConnectionHandler(mCM);
332
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700333 // Register for misc other intent broadcasts.
334 IntentFilter intentFilter =
335 new IntentFilter(Intent.ACTION_AIRPLANE_MODE_CHANGED);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700336 intentFilter.addAction(TelephonyIntents.ACTION_ANY_DATA_CONNECTION_STATE_CHANGED);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700337 intentFilter.addAction(TelephonyIntents.ACTION_SIM_STATE_CHANGED);
338 intentFilter.addAction(TelephonyIntents.ACTION_RADIO_TECHNOLOGY_CHANGED);
339 intentFilter.addAction(TelephonyIntents.ACTION_SERVICE_STATE_CHANGED);
340 intentFilter.addAction(TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700341 registerReceiver(mReceiver, intentFilter);
342
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700343 //set the default values for the preferences in the phone.
344 PreferenceManager.setDefaultValues(this, R.xml.network_setting, false);
345
346 PreferenceManager.setDefaultValues(this, R.xml.call_feature_setting, false);
347
348 // Make sure the audio mode (along with some
349 // audio-mode-related state of our own) is initialized
350 // correctly, given the current state of the phone.
351 PhoneUtils.setAudioMode(mCM);
352 }
353
Santos Cordon52bc81b2014-10-07 19:55:12 -0700354 cdmaOtaProvisionData = new OtaUtils.CdmaOtaProvisionData();
355 cdmaOtaConfigData = new OtaUtils.CdmaOtaConfigData();
356 cdmaOtaScreenState = new OtaUtils.CdmaOtaScreenState();
357 cdmaOtaInCallScreenUiState = new OtaUtils.CdmaOtaInCallScreenUiState();
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700358
Santos Cordon76aaf482015-04-08 10:58:27 -0700359 simActivationManager = new SimActivationManager();
360
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700361 // XXX pre-load the SimProvider so that it's ready
362 resolver.getType(Uri.parse("content://icc/adn"));
363
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700364 // TODO: Register for Cdma Information Records
365 // phone.registerCdmaInformationRecord(mHandler, EVENT_UNSOL_CDMA_INFO_RECORD, null);
366
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700367 // Read HAC settings and configure audio hardware
368 if (getResources().getBoolean(R.bool.hac_enabled)) {
Stuart Scottdcf40a92014-12-09 10:45:01 -0800369 int hac = android.provider.Settings.System.getInt(
370 getContentResolver(),
371 android.provider.Settings.System.HEARING_AID,
372 0);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700373 AudioManager audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
Andrew Leefb7f92e2015-02-26 16:23:32 -0800374 audioManager.setParameter(SettingsConstants.HAC_KEY,
375 hac == SettingsConstants.HAC_ENABLED
376 ? SettingsConstants.HAC_VAL_ON : SettingsConstants.HAC_VAL_OFF);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700377 }
Santos Cordonff506f52013-11-21 19:13:19 -0800378 }
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700379
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700380 /**
381 * Returns the singleton instance of the PhoneApp.
382 */
Sailesh Nepal1eaf22b2014-02-22 17:00:49 -0800383 public static PhoneGlobals getInstance() {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700384 if (sMe == null) {
385 throw new IllegalStateException("No PhoneGlobals here!");
386 }
387 return sMe;
388 }
389
390 /**
391 * Returns the singleton instance of the PhoneApp if running as the
392 * primary user, otherwise null.
393 */
394 static PhoneGlobals getInstanceIfPrimary() {
395 return sMe;
396 }
397
398 /**
Stuart Scottdcf40a92014-12-09 10:45:01 -0800399 * Returns the default phone.
400 *
Andrew Lee385019f2014-11-24 14:19:50 -0800401 * WARNING: This method should be used carefully, now that there may be multiple phones.
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700402 */
Andrew Lee83383e42014-10-31 12:42:28 -0700403 public static Phone getPhone() {
Stuart Scottdcf40a92014-12-09 10:45:01 -0800404 return PhoneFactory.getDefaultPhone();
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700405 }
406
Andrew Lee2fcb6c32014-12-04 14:52:35 -0800407 public static Phone getPhone(int subId) {
408 return PhoneFactory.getPhone(SubscriptionManager.getPhoneId(subId));
Andrew Lee385019f2014-11-24 14:19:50 -0800409 }
410
Santos Cordonde10b752013-09-19 04:11:33 -0700411 /* package */ CallManager getCallManager() {
412 return mCM;
413 }
414
Chris Manton4e9fa912015-06-19 11:26:57 -0700415 public PersistableBundle getCarrierConfig() {
Shishir Agrawald3480e02016-01-25 13:05:49 -0800416 return getCarrierConfigForSubId(SubscriptionManager.getDefaultSubscriptionId());
Jonathan Basseri89b0ab42015-05-01 10:52:40 -0700417 }
418
Chris Manton4e9fa912015-06-19 11:26:57 -0700419 public PersistableBundle getCarrierConfigForSubId(int subId) {
Jonathan Basseri89b0ab42015-05-01 10:52:40 -0700420 return configLoader.getConfigForSubId(subId);
Junda Liu605148f2015-04-28 15:23:40 -0700421 }
422
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700423 /**
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700424 * Handles OTASP-related events from the telephony layer.
425 *
426 * While an OTASP call is active, the CallNotifier forwards
427 * OTASP-related telephony events to this method.
428 */
429 void handleOtaspEvent(Message msg) {
430 if (DBG) Log.d(LOG_TAG, "handleOtaspEvent(message " + msg + ")...");
431
432 if (otaUtils == null) {
433 // We shouldn't be getting OTASP events without ever
434 // having started the OTASP call in the first place!
435 Log.w(LOG_TAG, "handleOtaEvents: got an event but otaUtils is null! "
436 + "message = " + msg);
437 return;
438 }
439
440 otaUtils.onOtaProvisionStatusChanged((AsyncResult) msg.obj);
441 }
442
443 /**
444 * Similarly, handle the disconnect event of an OTASP call
445 * by forwarding it to the OtaUtils instance.
446 */
447 /* package */ void handleOtaspDisconnect() {
448 if (DBG) Log.d(LOG_TAG, "handleOtaspDisconnect()...");
449
450 if (otaUtils == null) {
451 // We shouldn't be getting OTASP events without ever
452 // having started the OTASP call in the first place!
453 Log.w(LOG_TAG, "handleOtaspDisconnect: otaUtils is null!");
454 return;
455 }
456
457 otaUtils.onOtaspDisconnect();
458 }
459
460 /**
461 * Sets the activity responsible for un-PUK-blocking the device
462 * so that we may close it when we receive a positive result.
463 * mPUKEntryActivity is also used to indicate to the device that
464 * we are trying to un-PUK-lock the phone. In other words, iff
465 * it is NOT null, then we are trying to unlock and waiting for
466 * the SIM to move to READY state.
467 *
468 * @param activity is the activity to close when PUK has
469 * finished unlocking. Can be set to null to indicate the unlock
470 * or SIM READYing process is over.
471 */
472 void setPukEntryActivity(Activity activity) {
473 mPUKEntryActivity = activity;
474 }
475
476 Activity getPUKEntryActivity() {
477 return mPUKEntryActivity;
478 }
479
480 /**
481 * Sets the dialog responsible for notifying the user of un-PUK-
482 * blocking - SIM READYing progress, so that we may dismiss it
483 * when we receive a positive result.
484 *
485 * @param dialog indicates the progress dialog informing the user
486 * of the state of the device. Dismissed upon completion of
487 * READYing process
488 */
489 void setPukEntryProgressDialog(ProgressDialog dialog) {
490 mPUKEntryProgressDialog = dialog;
491 }
492
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700493 /**
494 * Controls whether or not the screen is allowed to sleep.
495 *
496 * Once sleep is allowed (WakeState is SLEEP), it will rely on the
497 * settings for the poke lock to determine when to timeout and let
498 * the device sleep {@link PhoneGlobals#setScreenTimeout}.
499 *
500 * @param ws tells the device to how to wake.
501 */
502 /* package */ void requestWakeState(WakeState ws) {
503 if (VDBG) Log.d(LOG_TAG, "requestWakeState(" + ws + ")...");
504 synchronized (this) {
505 if (mWakeState != ws) {
506 switch (ws) {
507 case PARTIAL:
508 // acquire the processor wake lock, and release the FULL
509 // lock if it is being held.
510 mPartialWakeLock.acquire();
511 if (mWakeLock.isHeld()) {
512 mWakeLock.release();
513 }
514 break;
515 case FULL:
516 // acquire the full wake lock, and release the PARTIAL
517 // lock if it is being held.
518 mWakeLock.acquire();
519 if (mPartialWakeLock.isHeld()) {
520 mPartialWakeLock.release();
521 }
522 break;
523 case SLEEP:
524 default:
525 // release both the PARTIAL and FULL locks.
526 if (mWakeLock.isHeld()) {
527 mWakeLock.release();
528 }
529 if (mPartialWakeLock.isHeld()) {
530 mPartialWakeLock.release();
531 }
532 break;
533 }
534 mWakeState = ws;
535 }
536 }
537 }
538
539 /**
540 * If we are not currently keeping the screen on, then poke the power
541 * manager to wake up the screen for the user activity timeout duration.
542 */
543 /* package */ void wakeUpScreen() {
544 synchronized (this) {
545 if (mWakeState == WakeState.SLEEP) {
546 if (DBG) Log.d(LOG_TAG, "pulse screen lock");
Dianne Hackborn148769b2015-07-13 17:55:47 -0700547 mPowerManager.wakeUp(SystemClock.uptimeMillis(), "android.phone:WAKE");
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700548 }
549 }
550 }
551
552 /**
553 * Sets the wake state and screen timeout based on the current state
554 * of the phone, and the current state of the in-call UI.
555 *
556 * This method is a "UI Policy" wrapper around
557 * {@link PhoneGlobals#requestWakeState} and {@link PhoneGlobals#setScreenTimeout}.
558 *
559 * It's safe to call this method regardless of the state of the Phone
560 * (e.g. whether or not it's idle), and regardless of the state of the
561 * Phone UI (e.g. whether or not the InCallScreen is active.)
562 */
563 /* package */ void updateWakeState() {
564 PhoneConstants.State state = mCM.getState();
565
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700566 // True if the speakerphone is in use. (If so, we *always* use
567 // the default timeout. Since the user is obviously not holding
568 // the phone up to his/her face, we don't need to worry about
569 // false touches, and thus don't need to turn the screen off so
570 // aggressively.)
571 // Note that we need to make a fresh call to this method any
572 // time the speaker state changes. (That happens in
573 // PhoneUtils.turnOnSpeaker().)
574 boolean isSpeakerInUse = (state == PhoneConstants.State.OFFHOOK) && PhoneUtils.isSpeakerOn(this);
575
576 // TODO (bug 1440854): The screen timeout *might* also need to
577 // depend on the bluetooth state, but this isn't as clear-cut as
578 // the speaker state (since while using BT it's common for the
579 // user to put the phone straight into a pocket, in which case the
580 // timeout should probably still be short.)
581
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700582 // Decide whether to force the screen on or not.
583 //
584 // Force the screen to be on if the phone is ringing or dialing,
585 // or if we're displaying the "Call ended" UI for a connection in
586 // the "disconnected" state.
587 // However, if the phone is disconnected while the user is in the
588 // middle of selecting a quick response message, we should not force
589 // the screen to be on.
590 //
591 boolean isRinging = (state == PhoneConstants.State.RINGING);
Stuart Scottdcf40a92014-12-09 10:45:01 -0800592 boolean isDialing = (mCM.getFgPhone().getForegroundCall().getState() == Call.State.DIALING);
Jay Shrauner6fe8fd62013-09-16 19:39:30 -0700593 boolean keepScreenOn = isRinging || isDialing;
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700594 // keepScreenOn == true means we'll hold a full wake lock:
595 requestWakeState(keepScreenOn ? WakeState.FULL : WakeState.SLEEP);
596 }
597
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700598 KeyguardManager getKeyguardManager() {
599 return mKeyguardManager;
600 }
601
602 private void onMMIComplete(AsyncResult r) {
603 if (VDBG) Log.d(LOG_TAG, "onMMIComplete()...");
604 MmiCode mmiCode = (MmiCode) r.result;
Stuart Scottdcf40a92014-12-09 10:45:01 -0800605 PhoneUtils.displayMMIComplete(mmiCode.getPhone(), getInstance(), mmiCode, null, null);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700606 }
607
Stuart Scottdcf40a92014-12-09 10:45:01 -0800608 private void initForNewRadioTechnology(int phoneId) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700609 if (DBG) Log.d(LOG_TAG, "initForNewRadioTechnology...");
610
Stuart Scottdcf40a92014-12-09 10:45:01 -0800611 final Phone phone = PhoneFactory.getPhone(phoneId);
Santos Cordonc593d002015-06-03 15:41:15 -0700612 if (phone == null || !TelephonyCapabilities.supportsOtasp(phone)) {
613 // Clean up OTA for non-CDMA since it is only valid for CDMA.
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700614 clearOtaState();
615 }
616
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700617 notifier.updateCallNotifierRegistrationsAfterRadioTechnologyChange();
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700618 }
619
Santos Cordone18902f2016-03-22 17:16:04 -0700620 private void handleAirplaneModeChange(int newMode) {
621 if (newMode == AIRPLANE_ON) {
622 // If we are trying to turn off the radio, make sure there are no active
623 // emergency calls. If there are, switch airplane mode back to off.
624 if (PhoneUtils.isInEmergencyCall(mCM)) {
625 // Switch airplane mode back to off.
626 ConnectivityManager.from(this).setAirplaneMode(false);
627 Toast.makeText(this, R.string.radio_off_during_emergency_call, Toast.LENGTH_LONG)
628 .show();
629 Log.i(LOG_TAG, "Ignoring airplane mode: emergency call. Turning airplane off");
630 } else {
631 Log.i(LOG_TAG, "Turning radio off - airplane");
632 PhoneUtils.setRadioPower(false);
633 }
634 } else {
635 Log.i(LOG_TAG, "Turning radio on - airplane");
636 PhoneUtils.setRadioPower(true);
637 }
638 }
639
Santos Cordon593ab382013-08-06 21:58:23 -0700640 /**
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700641 * Receiver for misc intent broadcasts the Phone app cares about.
642 */
643 private class PhoneAppBroadcastReceiver extends BroadcastReceiver {
644 @Override
645 public void onReceive(Context context, Intent intent) {
646 String action = intent.getAction();
647 if (action.equals(Intent.ACTION_AIRPLANE_MODE_CHANGED)) {
Santos Cordone18902f2016-03-22 17:16:04 -0700648 int airplaneMode = Settings.Global.getInt(getContentResolver(),
649 Settings.Global.AIRPLANE_MODE_ON, AIRPLANE_OFF);
650 // Treat any non-OFF values as ON.
651 if (airplaneMode != AIRPLANE_OFF) {
652 airplaneMode = AIRPLANE_ON;
653 }
654 handleAirplaneModeChange(airplaneMode);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700655 } else if (action.equals(TelephonyIntents.ACTION_ANY_DATA_CONNECTION_STATE_CHANGED)) {
Stuart Scottdcf40a92014-12-09 10:45:01 -0800656 int subId = intent.getIntExtra(PhoneConstants.SUBSCRIPTION_KEY,
657 SubscriptionManager.INVALID_SUBSCRIPTION_ID);
658 int phoneId = SubscriptionManager.getPhoneId(subId);
659 String state = intent.getStringExtra(PhoneConstants.STATE_KEY);
660 if (VDBG) {
661 Log.d(LOG_TAG, "mReceiver: ACTION_ANY_DATA_CONNECTION_STATE_CHANGED");
662 Log.d(LOG_TAG, "- state: " + state);
663 Log.d(LOG_TAG, "- reason: "
664 + intent.getStringExtra(PhoneConstants.STATE_CHANGE_REASON_KEY));
665 Log.d(LOG_TAG, "- subId: " + subId);
666 Log.d(LOG_TAG, "- phoneId: " + phoneId);
667 }
668 Phone phone = SubscriptionManager.isValidPhoneId(phoneId) ?
669 PhoneFactory.getPhone(phoneId) : PhoneFactory.getDefaultPhone();
Santos Cordonc593d002015-06-03 15:41:15 -0700670
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700671 // The "data disconnected due to roaming" notification is shown
672 // if (a) you have the "data roaming" feature turned off, and
673 // (b) you just lost data connectivity because you're roaming.
674 boolean disconnectedDueToRoaming =
675 !phone.getDataRoamingEnabled()
Stuart Scottdcf40a92014-12-09 10:45:01 -0800676 && PhoneConstants.DataState.DISCONNECTED.equals(state)
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700677 && Phone.REASON_ROAMING_ON.equals(
678 intent.getStringExtra(PhoneConstants.STATE_CHANGE_REASON_KEY));
Yorke Lee4d2db1c2014-11-06 11:37:09 -0800679 if (mDataDisconnectedDueToRoaming != disconnectedDueToRoaming) {
680 mDataDisconnectedDueToRoaming = disconnectedDueToRoaming;
681 mHandler.sendEmptyMessage(disconnectedDueToRoaming
682 ? EVENT_DATA_ROAMING_DISCONNECTED : EVENT_DATA_ROAMING_OK);
683 }
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700684 } else if ((action.equals(TelephonyIntents.ACTION_SIM_STATE_CHANGED)) &&
685 (mPUKEntryActivity != null)) {
686 // if an attempt to un-PUK-lock the device was made, while we're
687 // receiving this state change notification, notify the handler.
688 // NOTE: This is ONLY triggered if an attempt to un-PUK-lock has
689 // been attempted.
690 mHandler.sendMessage(mHandler.obtainMessage(EVENT_SIM_STATE_CHANGED,
691 intent.getStringExtra(IccCardConstants.INTENT_KEY_ICC_STATE)));
692 } else if (action.equals(TelephonyIntents.ACTION_RADIO_TECHNOLOGY_CHANGED)) {
693 String newPhone = intent.getStringExtra(PhoneConstants.PHONE_NAME_KEY);
Stuart Scottdcf40a92014-12-09 10:45:01 -0800694 int phoneId = intent.getIntExtra(PhoneConstants.PHONE_KEY,
695 SubscriptionManager.INVALID_PHONE_INDEX);
696 Log.d(LOG_TAG, "Radio technology switched. Now " + newPhone + " (" + phoneId
697 + ") is active.");
698 initForNewRadioTechnology(phoneId);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700699 } else if (action.equals(TelephonyIntents.ACTION_SERVICE_STATE_CHANGED)) {
700 handleServiceStateChanged(intent);
701 } else if (action.equals(TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED)) {
Stuart Scottdcf40a92014-12-09 10:45:01 -0800702 if (TelephonyCapabilities.supportsEcm(mCM.getFgPhone())) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700703 Log.d(LOG_TAG, "Emergency Callback Mode arrived in PhoneApp.");
704 // Start Emergency Callback Mode service
705 if (intent.getBooleanExtra("phoneinECMState", false)) {
706 context.startService(new Intent(context,
707 EmergencyCallbackModeService.class));
708 }
709 } else {
710 // It doesn't make sense to get ACTION_EMERGENCY_CALLBACK_MODE_CHANGED
711 // on a device that doesn't support ECM in the first place.
712 Log.e(LOG_TAG, "Got ACTION_EMERGENCY_CALLBACK_MODE_CHANGED, "
Stuart Scottdcf40a92014-12-09 10:45:01 -0800713 + "but ECM isn't supported for phone: "
714 + mCM.getFgPhone().getPhoneName());
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700715 }
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700716 }
717 }
718 }
719
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700720 private void handleServiceStateChanged(Intent intent) {
721 /**
722 * This used to handle updating EriTextWidgetProvider this routine
723 * and and listening for ACTION_SERVICE_STATE_CHANGED intents could
724 * be removed. But leaving just in case it might be needed in the near
725 * future.
726 */
727
728 // If service just returned, start sending out the queued messages
Santos Cordonc593d002015-06-03 15:41:15 -0700729 Bundle extras = intent.getExtras();
730 if (extras != null) {
731 ServiceState ss = ServiceState.newFromBundle(extras);
732 if (ss != null) {
733 int state = ss.getState();
734 notificationMgr.updateNetworkSelection(state);
735 }
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700736 }
737 }
738
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700739 // it is safe to call clearOtaState() even if the InCallScreen isn't active
740 public void clearOtaState() {
741 if (DBG) Log.d(LOG_TAG, "- clearOtaState ...");
Jay Shrauner6fe8fd62013-09-16 19:39:30 -0700742 if (otaUtils != null) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700743 otaUtils.cleanOtaScreen(true);
744 if (DBG) Log.d(LOG_TAG, " - clearOtaState clears OTA screen");
745 }
746 }
747
748 // it is safe to call dismissOtaDialogs() even if the InCallScreen isn't active
749 public void dismissOtaDialogs() {
750 if (DBG) Log.d(LOG_TAG, "- dismissOtaDialogs ...");
Jay Shrauner6fe8fd62013-09-16 19:39:30 -0700751 if (otaUtils != null) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700752 otaUtils.dismissAllOtaDialogs();
753 if (DBG) Log.d(LOG_TAG, " - dismissOtaDialogs clears OTA dialogs");
754 }
755 }
756
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700757 /**
Tyler Gunn9c1071f2014-12-09 10:07:54 -0800758 * Triggers a refresh of the message waiting (voicemail) indicator.
759 *
760 * @param subId the subscription id we should refresh the notification for.
761 */
762 public void refreshMwiIndicator(int subId) {
763 notificationMgr.refreshMwi(subId);
764 }
765
766 /**
Nancy Chenbb49d412015-07-23 13:54:16 -0700767 * Dismisses the message waiting (voicemail) indicator.
768 *
769 * @param subId the subscription id we should dismiss the notification for.
770 */
771 public void clearMwiIndicator(int subId) {
772 notificationMgr.updateMwi(subId, false);
773 }
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700774}