blob: cdd1eb1cc9b0ad4be58c0b1beb99f2fccdf1ff7c [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;
Brad Ebinger3fa43462016-04-12 16:06:48 -070040import android.os.UserManager;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070041import android.preference.PreferenceManager;
Sanket Padawe4c699232016-02-09 11:07:22 -080042import android.provider.Settings;
Junda Liu12f7d802015-05-01 12:06:44 -070043import android.telephony.CarrierConfigManager;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070044import android.telephony.ServiceState;
Andrew Lee385019f2014-11-24 14:19:50 -080045import android.telephony.SubscriptionManager;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070046import android.util.Log;
Santos Cordone18902f2016-03-22 17:16:04 -070047import android.widget.Toast;
Ta-wei Yenb29425b2016-09-21 17:28:14 -070048
Santos Cordon7d4ddf62013-07-10 11:58:08 -070049import com.android.internal.telephony.Call;
50import com.android.internal.telephony.CallManager;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070051import com.android.internal.telephony.IccCardConstants;
52import com.android.internal.telephony.MmiCode;
53import com.android.internal.telephony.Phone;
54import com.android.internal.telephony.PhoneConstants;
55import com.android.internal.telephony.PhoneFactory;
56import com.android.internal.telephony.TelephonyCapabilities;
57import com.android.internal.telephony.TelephonyIntents;
Santos Cordon352ff652014-05-30 01:41:45 -070058import com.android.phone.common.CallLogAsync;
Andrew Leefb7f92e2015-02-26 16:23:32 -080059import com.android.phone.settings.SettingsConstants;
Brad Ebinger3fa43462016-04-12 16:06:48 -070060import com.android.services.telephony.sip.SipUtil;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070061
62/**
63 * Global state for the telephony subsystem when running in the primary
64 * phone process.
65 */
Sailesh Nepalbf900542014-07-15 16:18:32 -070066public class PhoneGlobals extends ContextWrapper {
Andrew Lee83383e42014-10-31 12:42:28 -070067 public static final String LOG_TAG = "PhoneApp";
Santos Cordon7d4ddf62013-07-10 11:58:08 -070068
69 /**
70 * Phone app-wide debug level:
71 * 0 - no debug logging
72 * 1 - normal debug logging if ro.debuggable is set (which is true in
73 * "eng" and "userdebug" builds but not "user" builds)
74 * 2 - ultra-verbose debug logging
75 *
76 * Most individual classes in the phone app have a local DBG constant,
77 * typically set to
78 * (PhoneApp.DBG_LEVEL >= 1) && (SystemProperties.getInt("ro.debuggable", 0) == 1)
79 * or else
80 * (PhoneApp.DBG_LEVEL >= 2)
81 * depending on the desired verbosity.
82 *
83 * ***** DO NOT SUBMIT WITH DBG_LEVEL > 0 *************
84 */
Andrew Lee88b51e22014-10-29 15:48:51 -070085 public static final int DBG_LEVEL = 0;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070086
87 private static final boolean DBG =
88 (PhoneGlobals.DBG_LEVEL >= 1) && (SystemProperties.getInt("ro.debuggable", 0) == 1);
89 private static final boolean VDBG = (PhoneGlobals.DBG_LEVEL >= 2);
90
91 // Message codes; see mHandler below.
92 private static final int EVENT_SIM_NETWORK_LOCKED = 3;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070093 private static final int EVENT_SIM_STATE_CHANGED = 8;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070094 private static final int EVENT_DATA_ROAMING_DISCONNECTED = 10;
95 private static final int EVENT_DATA_ROAMING_OK = 11;
96 private static final int EVENT_UNSOL_CDMA_INFO_RECORD = 12;
Brad Ebinger3fa43462016-04-12 16:06:48 -070097 private static final int EVENT_RESTART_SIP = 13;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070098
99 // The MMI codes are also used by the InCallScreen.
100 public static final int MMI_INITIATE = 51;
101 public static final int MMI_COMPLETE = 52;
102 public static final int MMI_CANCEL = 53;
103 // Don't use message codes larger than 99 here; those are reserved for
104 // the individual Activities of the Phone UI.
105
Santos Cordone18902f2016-03-22 17:16:04 -0700106 public static final int AIRPLANE_ON = 1;
107 public static final int AIRPLANE_OFF = 0;
108
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700109 /**
110 * Allowable values for the wake lock code.
111 * SLEEP means the device can be put to sleep.
112 * PARTIAL means wake the processor, but we display can be kept off.
113 * FULL means wake both the processor and the display.
114 */
115 public enum WakeState {
116 SLEEP,
117 PARTIAL,
118 FULL
119 }
120
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700121 private static PhoneGlobals sMe;
122
123 // A few important fields we expose to the rest of the package
124 // directly (rather than thru set/get methods) for efficiency.
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700125 CallController callController;
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700126 CallManager mCM;
Santos Cordon63a84242013-07-23 13:32:52 -0700127 CallNotifier notifier;
128 CallerInfoCache callerInfoCache;
Santos Cordon63a84242013-07-23 13:32:52 -0700129 NotificationMgr notificationMgr;
Andrew Lee9431b832015-03-09 18:46:45 -0700130 public PhoneInterfaceManager phoneMgr;
Jonathan Basseri6465afd2015-02-25 13:05:57 -0800131 CarrierConfigLoader configLoader;
Santos Cordon63a84242013-07-23 13:32:52 -0700132
Santos Cordon69a69192013-08-22 14:25:42 -0700133 private CallGatewayManager callGatewayManager;
Sandeep Kuntade73a6a2014-10-15 18:45:56 +0530134 private Phone phoneInEcm;
Santos Cordon63a84242013-07-23 13:32:52 -0700135
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700136 static boolean sVoiceCapable = true;
137
Santos Cordonc593d002015-06-03 15:41:15 -0700138 // TODO: Remove, no longer used.
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700139 CdmaPhoneCallState cdmaPhoneCallState;
140
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700141 // The currently-active PUK entry activity and progress dialog.
142 // Normally, these are the Emergency Dialer and the subsequent
143 // progress dialog. null if there is are no such objects in
144 // the foreground.
145 private Activity mPUKEntryActivity;
146 private ProgressDialog mPUKEntryProgressDialog;
147
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 Handler mHandler = new Handler() {
161 @Override
162 public void handleMessage(Message msg) {
163 PhoneConstants.State phoneState;
164 switch (msg.what) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700165 // TODO: This event should be handled by the lock screen, just
166 // like the "SIM missing" and "Sim locked" cases (bug 1804111).
167 case EVENT_SIM_NETWORK_LOCKED:
Jonathan Basseri9504c6b2015-06-04 14:23:32 -0700168 if (getCarrierConfig().getBoolean(
169 CarrierConfigManager.KEY_IGNORE_SIM_NETWORK_LOCKED_EVENTS_BOOL)) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700170 // Some products don't have the concept of a "SIM network lock"
171 Log.i(LOG_TAG, "Ignoring EVENT_SIM_NETWORK_LOCKED event; "
172 + "not showing 'SIM network unlock' PIN entry screen");
173 } else {
174 // Normal case: show the "SIM network unlock" PIN entry screen.
175 // The user won't be able to do anything else until
176 // they enter a valid SIM network PIN.
177 Log.i(LOG_TAG, "show sim depersonal panel");
Tyler Gunn52a37072015-08-24 14:23:19 -0700178 IccNetworkDepersonalizationPanel.showDialog();
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700179 }
180 break;
181
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700182 case EVENT_DATA_ROAMING_DISCONNECTED:
183 notificationMgr.showDataDisconnectedRoaming();
184 break;
185
186 case EVENT_DATA_ROAMING_OK:
187 notificationMgr.hideDataDisconnectedRoaming();
188 break;
189
190 case MMI_COMPLETE:
191 onMMIComplete((AsyncResult) msg.obj);
192 break;
193
194 case MMI_CANCEL:
Stuart Scottdcf40a92014-12-09 10:45:01 -0800195 PhoneUtils.cancelMmiCode(mCM.getFgPhone());
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700196 break;
197
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700198 case EVENT_SIM_STATE_CHANGED:
199 // Marks the event where the SIM goes into ready state.
200 // Right now, this is only used for the PUK-unlocking
201 // process.
202 if (msg.obj.equals(IccCardConstants.INTENT_VALUE_ICC_READY)) {
203 // when the right event is triggered and there
204 // are UI objects in the foreground, we close
205 // them to display the lock panel.
206 if (mPUKEntryActivity != null) {
207 mPUKEntryActivity.finish();
208 mPUKEntryActivity = null;
209 }
210 if (mPUKEntryProgressDialog != null) {
211 mPUKEntryProgressDialog.dismiss();
212 mPUKEntryProgressDialog = null;
213 }
214 }
215 break;
216
217 case EVENT_UNSOL_CDMA_INFO_RECORD:
218 //TODO: handle message here;
219 break;
Brad Ebinger3fa43462016-04-12 16:06:48 -0700220 case EVENT_RESTART_SIP:
221 // This should only run if the Phone process crashed and was restarted. We do
222 // not want this running if the device is still in the FBE encrypted state.
223 // This is the same procedure that is triggered in the SipBroadcastReceiver
224 // upon BOOT_COMPLETED.
225 UserManager userManager = UserManager.get(sMe);
226 if (userManager != null && userManager.isUserUnlocked()) {
227 SipUtil.startSipService();
228 }
229 break;
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700230 }
231 }
232 };
233
234 public PhoneGlobals(Context context) {
235 super(context);
236 sMe = this;
237 }
238
239 public void onCreate() {
240 if (VDBG) Log.v(LOG_TAG, "onCreate()...");
241
242 ContentResolver resolver = getContentResolver();
243
244 // Cache the "voice capable" flag.
245 // This flag currently comes from a resource (which is
246 // overrideable on a per-product basis):
247 sVoiceCapable =
248 getResources().getBoolean(com.android.internal.R.bool.config_voice_capable);
249 // ...but this might eventually become a PackageManager "system
250 // feature" instead, in which case we'd do something like:
251 // sVoiceCapable =
252 // getPackageManager().hasSystemFeature(PackageManager.FEATURE_TELEPHONY_VOICE_CALLS);
253
Stuart Scottdcf40a92014-12-09 10:45:01 -0800254 if (mCM == null) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700255 // Initialize the telephony framework
256 PhoneFactory.makeDefaultPhones(this);
257
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700258 // Start TelephonyDebugService After the default phone is created.
259 Intent intent = new Intent(this, TelephonyDebugService.class);
260 startService(intent);
261
262 mCM = CallManager.getInstance();
Stuart Scottdcf40a92014-12-09 10:45:01 -0800263 for (Phone phone : PhoneFactory.getPhones()) {
264 mCM.registerPhone(phone);
Stuart Scottdcf40a92014-12-09 10:45:01 -0800265 }
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700266
267 // Create the NotificationMgr singleton, which is used to display
268 // status bar icons and control other status bar behavior.
269 notificationMgr = NotificationMgr.init(this);
270
Brad Ebinger3fa43462016-04-12 16:06:48 -0700271 // If PhoneGlobals has crashed and is being restarted, then restart.
272 mHandler.sendEmptyMessage(EVENT_RESTART_SIP);
273
Anthony Lee03ebdfc2015-07-27 08:12:02 -0700274 // Create an instance of CdmaPhoneCallState and initialize it to IDLE
275 cdmaPhoneCallState = new CdmaPhoneCallState();
276 cdmaPhoneCallState.CdmaPhoneCallStateInit();
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700277
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700278 // before registering for phone state changes
279 mPowerManager = (PowerManager) getSystemService(Context.POWER_SERVICE);
280 mWakeLock = mPowerManager.newWakeLock(PowerManager.FULL_WAKE_LOCK, LOG_TAG);
281 // lock used to keep the processor awake, when we don't care for the display.
282 mPartialWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK
283 | PowerManager.ON_AFTER_RELEASE, LOG_TAG);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700284
285 mKeyguardManager = (KeyguardManager) getSystemService(Context.KEYGUARD_SERVICE);
286
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700287 // Get UpdateLock to suppress system-update related events (e.g. dialog show-up)
288 // during phone calls.
289 mUpdateLock = new UpdateLock("phone");
290
291 if (DBG) Log.d(LOG_TAG, "onCreate: mUpdateLock: " + mUpdateLock);
292
293 CallLogger callLogger = new CallLogger(this, new CallLogAsync());
294
Jay Shrauner21a75342013-11-25 16:14:43 -0800295 callGatewayManager = CallGatewayManager.getInstance();
Santos Cordon69a69192013-08-22 14:25:42 -0700296
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700297 // Create the CallController singleton, which is the interface
298 // to the telephony layer for user-initiated telephony functionality
299 // (like making outgoing calls.)
Santos Cordon69a69192013-08-22 14:25:42 -0700300 callController = CallController.init(this, callLogger, callGatewayManager);
301
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700302 // Create the CallerInfoCache singleton, which remembers custom ring tone and
303 // send-to-voicemail settings.
304 //
305 // The asynchronous caching will start just after this call.
306 callerInfoCache = CallerInfoCache.init(this);
307
Stuart Scottdcf40a92014-12-09 10:45:01 -0800308 phoneMgr = PhoneInterfaceManager.init(this, PhoneFactory.getDefaultPhone());
Santos Cordon406c0342013-08-28 00:07:47 -0700309
Jonathan Basseri6465afd2015-02-25 13:05:57 -0800310 configLoader = CarrierConfigLoader.init(this);
311
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700312 // Create the CallNotifer singleton, which handles
313 // asynchronous events from the telephony layer (like
314 // launching the incoming-call UI when an incoming call comes
315 // in.)
Brad Ebingera9c6b6d2016-01-07 17:24:16 -0800316 notifier = CallNotifier.init(this);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700317
Stuart Scottdcf40a92014-12-09 10:45:01 -0800318 PhoneUtils.registerIccStatus(mHandler, EVENT_SIM_NETWORK_LOCKED);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700319
320 // register for MMI/USSD
321 mCM.registerForMmiComplete(mHandler, MMI_COMPLETE, null);
322
323 // register connection tracking to PhoneUtils
324 PhoneUtils.initializeConnectionHandler(mCM);
325
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700326 // Register for misc other intent broadcasts.
327 IntentFilter intentFilter =
328 new IntentFilter(Intent.ACTION_AIRPLANE_MODE_CHANGED);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700329 intentFilter.addAction(TelephonyIntents.ACTION_ANY_DATA_CONNECTION_STATE_CHANGED);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700330 intentFilter.addAction(TelephonyIntents.ACTION_SIM_STATE_CHANGED);
331 intentFilter.addAction(TelephonyIntents.ACTION_RADIO_TECHNOLOGY_CHANGED);
332 intentFilter.addAction(TelephonyIntents.ACTION_SERVICE_STATE_CHANGED);
333 intentFilter.addAction(TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700334 registerReceiver(mReceiver, intentFilter);
335
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700336 //set the default values for the preferences in the phone.
pkanward702e542017-02-08 15:44:54 -0800337 PreferenceManager.setDefaultValues(this, R.xml.network_setting_fragment, false);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700338
339 PreferenceManager.setDefaultValues(this, R.xml.call_feature_setting, false);
340
341 // Make sure the audio mode (along with some
342 // audio-mode-related state of our own) is initialized
343 // correctly, given the current state of the phone.
344 PhoneUtils.setAudioMode(mCM);
345 }
346
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700347 // XXX pre-load the SimProvider so that it's ready
348 resolver.getType(Uri.parse("content://icc/adn"));
349
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700350 // TODO: Register for Cdma Information Records
351 // phone.registerCdmaInformationRecord(mHandler, EVENT_UNSOL_CDMA_INFO_RECORD, null);
352
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700353 // Read HAC settings and configure audio hardware
354 if (getResources().getBoolean(R.bool.hac_enabled)) {
Stuart Scottdcf40a92014-12-09 10:45:01 -0800355 int hac = android.provider.Settings.System.getInt(
356 getContentResolver(),
357 android.provider.Settings.System.HEARING_AID,
358 0);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700359 AudioManager audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
Andrew Leefb7f92e2015-02-26 16:23:32 -0800360 audioManager.setParameter(SettingsConstants.HAC_KEY,
361 hac == SettingsConstants.HAC_ENABLED
362 ? SettingsConstants.HAC_VAL_ON : SettingsConstants.HAC_VAL_OFF);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700363 }
Santos Cordonff506f52013-11-21 19:13:19 -0800364 }
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700365
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700366 /**
367 * Returns the singleton instance of the PhoneApp.
368 */
Sailesh Nepal1eaf22b2014-02-22 17:00:49 -0800369 public static PhoneGlobals getInstance() {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700370 if (sMe == null) {
371 throw new IllegalStateException("No PhoneGlobals here!");
372 }
373 return sMe;
374 }
375
376 /**
377 * Returns the singleton instance of the PhoneApp if running as the
378 * primary user, otherwise null.
379 */
380 static PhoneGlobals getInstanceIfPrimary() {
381 return sMe;
382 }
383
384 /**
Stuart Scottdcf40a92014-12-09 10:45:01 -0800385 * Returns the default phone.
386 *
Andrew Lee385019f2014-11-24 14:19:50 -0800387 * WARNING: This method should be used carefully, now that there may be multiple phones.
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700388 */
Andrew Lee83383e42014-10-31 12:42:28 -0700389 public static Phone getPhone() {
Stuart Scottdcf40a92014-12-09 10:45:01 -0800390 return PhoneFactory.getDefaultPhone();
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700391 }
392
Andrew Lee2fcb6c32014-12-04 14:52:35 -0800393 public static Phone getPhone(int subId) {
394 return PhoneFactory.getPhone(SubscriptionManager.getPhoneId(subId));
Andrew Lee385019f2014-11-24 14:19:50 -0800395 }
396
Santos Cordonde10b752013-09-19 04:11:33 -0700397 /* package */ CallManager getCallManager() {
398 return mCM;
399 }
400
Chris Manton4e9fa912015-06-19 11:26:57 -0700401 public PersistableBundle getCarrierConfig() {
Shishir Agrawald3480e02016-01-25 13:05:49 -0800402 return getCarrierConfigForSubId(SubscriptionManager.getDefaultSubscriptionId());
Jonathan Basseri89b0ab42015-05-01 10:52:40 -0700403 }
404
Chris Manton4e9fa912015-06-19 11:26:57 -0700405 public PersistableBundle getCarrierConfigForSubId(int subId) {
Jonathan Basseri89b0ab42015-05-01 10:52:40 -0700406 return configLoader.getConfigForSubId(subId);
Junda Liu605148f2015-04-28 15:23:40 -0700407 }
408
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700409 /**
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700410 * Sets the activity responsible for un-PUK-blocking the device
411 * so that we may close it when we receive a positive result.
412 * mPUKEntryActivity is also used to indicate to the device that
413 * we are trying to un-PUK-lock the phone. In other words, iff
414 * it is NOT null, then we are trying to unlock and waiting for
415 * the SIM to move to READY state.
416 *
417 * @param activity is the activity to close when PUK has
418 * finished unlocking. Can be set to null to indicate the unlock
419 * or SIM READYing process is over.
420 */
421 void setPukEntryActivity(Activity activity) {
422 mPUKEntryActivity = activity;
423 }
424
425 Activity getPUKEntryActivity() {
426 return mPUKEntryActivity;
427 }
428
429 /**
430 * Sets the dialog responsible for notifying the user of un-PUK-
431 * blocking - SIM READYing progress, so that we may dismiss it
432 * when we receive a positive result.
433 *
434 * @param dialog indicates the progress dialog informing the user
435 * of the state of the device. Dismissed upon completion of
436 * READYing process
437 */
438 void setPukEntryProgressDialog(ProgressDialog dialog) {
439 mPUKEntryProgressDialog = dialog;
440 }
441
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700442 /**
443 * Controls whether or not the screen is allowed to sleep.
444 *
445 * Once sleep is allowed (WakeState is SLEEP), it will rely on the
446 * settings for the poke lock to determine when to timeout and let
447 * the device sleep {@link PhoneGlobals#setScreenTimeout}.
448 *
449 * @param ws tells the device to how to wake.
450 */
451 /* package */ void requestWakeState(WakeState ws) {
452 if (VDBG) Log.d(LOG_TAG, "requestWakeState(" + ws + ")...");
453 synchronized (this) {
454 if (mWakeState != ws) {
455 switch (ws) {
456 case PARTIAL:
457 // acquire the processor wake lock, and release the FULL
458 // lock if it is being held.
459 mPartialWakeLock.acquire();
460 if (mWakeLock.isHeld()) {
461 mWakeLock.release();
462 }
463 break;
464 case FULL:
465 // acquire the full wake lock, and release the PARTIAL
466 // lock if it is being held.
467 mWakeLock.acquire();
468 if (mPartialWakeLock.isHeld()) {
469 mPartialWakeLock.release();
470 }
471 break;
472 case SLEEP:
473 default:
474 // release both the PARTIAL and FULL locks.
475 if (mWakeLock.isHeld()) {
476 mWakeLock.release();
477 }
478 if (mPartialWakeLock.isHeld()) {
479 mPartialWakeLock.release();
480 }
481 break;
482 }
483 mWakeState = ws;
484 }
485 }
486 }
487
488 /**
489 * If we are not currently keeping the screen on, then poke the power
490 * manager to wake up the screen for the user activity timeout duration.
491 */
492 /* package */ void wakeUpScreen() {
493 synchronized (this) {
494 if (mWakeState == WakeState.SLEEP) {
495 if (DBG) Log.d(LOG_TAG, "pulse screen lock");
Dianne Hackborn148769b2015-07-13 17:55:47 -0700496 mPowerManager.wakeUp(SystemClock.uptimeMillis(), "android.phone:WAKE");
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700497 }
498 }
499 }
500
501 /**
502 * Sets the wake state and screen timeout based on the current state
503 * of the phone, and the current state of the in-call UI.
504 *
505 * This method is a "UI Policy" wrapper around
506 * {@link PhoneGlobals#requestWakeState} and {@link PhoneGlobals#setScreenTimeout}.
507 *
508 * It's safe to call this method regardless of the state of the Phone
509 * (e.g. whether or not it's idle), and regardless of the state of the
510 * Phone UI (e.g. whether or not the InCallScreen is active.)
511 */
512 /* package */ void updateWakeState() {
513 PhoneConstants.State state = mCM.getState();
514
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700515 // True if the speakerphone is in use. (If so, we *always* use
516 // the default timeout. Since the user is obviously not holding
517 // the phone up to his/her face, we don't need to worry about
518 // false touches, and thus don't need to turn the screen off so
519 // aggressively.)
520 // Note that we need to make a fresh call to this method any
521 // time the speaker state changes. (That happens in
522 // PhoneUtils.turnOnSpeaker().)
523 boolean isSpeakerInUse = (state == PhoneConstants.State.OFFHOOK) && PhoneUtils.isSpeakerOn(this);
524
525 // TODO (bug 1440854): The screen timeout *might* also need to
526 // depend on the bluetooth state, but this isn't as clear-cut as
527 // the speaker state (since while using BT it's common for the
528 // user to put the phone straight into a pocket, in which case the
529 // timeout should probably still be short.)
530
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700531 // Decide whether to force the screen on or not.
532 //
533 // Force the screen to be on if the phone is ringing or dialing,
534 // or if we're displaying the "Call ended" UI for a connection in
535 // the "disconnected" state.
536 // However, if the phone is disconnected while the user is in the
537 // middle of selecting a quick response message, we should not force
538 // the screen to be on.
539 //
540 boolean isRinging = (state == PhoneConstants.State.RINGING);
Stuart Scottdcf40a92014-12-09 10:45:01 -0800541 boolean isDialing = (mCM.getFgPhone().getForegroundCall().getState() == Call.State.DIALING);
Jay Shrauner6fe8fd62013-09-16 19:39:30 -0700542 boolean keepScreenOn = isRinging || isDialing;
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700543 // keepScreenOn == true means we'll hold a full wake lock:
544 requestWakeState(keepScreenOn ? WakeState.FULL : WakeState.SLEEP);
545 }
546
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700547 KeyguardManager getKeyguardManager() {
548 return mKeyguardManager;
549 }
550
551 private void onMMIComplete(AsyncResult r) {
552 if (VDBG) Log.d(LOG_TAG, "onMMIComplete()...");
553 MmiCode mmiCode = (MmiCode) r.result;
Stuart Scottdcf40a92014-12-09 10:45:01 -0800554 PhoneUtils.displayMMIComplete(mmiCode.getPhone(), getInstance(), mmiCode, null, null);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700555 }
556
fionaxu80126972017-02-01 17:01:26 -0800557 private void initForNewRadioTechnology() {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700558 if (DBG) Log.d(LOG_TAG, "initForNewRadioTechnology...");
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700559 notifier.updateCallNotifierRegistrationsAfterRadioTechnologyChange();
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700560 }
561
Chris Mantona09f3632016-02-09 14:48:42 -0800562 private void handleAirplaneModeChange(Context context, int newMode) {
563 int cellState = Settings.Global.getInt(context.getContentResolver(),
564 Settings.Global.CELL_ON, PhoneConstants.CELL_ON_FLAG);
565 boolean isAirplaneNewlyOn = (newMode == 1);
566 switch (cellState) {
567 case PhoneConstants.CELL_OFF_FLAG:
568 // Airplane mode does not affect the cell radio if user
569 // has turned it off.
570 break;
571 case PhoneConstants.CELL_ON_FLAG:
572 maybeTurnCellOff(context, isAirplaneNewlyOn);
573 break;
574 case PhoneConstants.CELL_OFF_DUE_TO_AIRPLANE_MODE_FLAG:
575 maybeTurnCellOn(context, isAirplaneNewlyOn);
576 break;
577 }
578 }
579
580 /*
581 * Returns true if the radio must be turned off when entering airplane mode.
582 */
583 private boolean isCellOffInAirplaneMode(Context context) {
584 String airplaneModeRadios = Settings.Global.getString(context.getContentResolver(),
585 Settings.Global.AIRPLANE_MODE_RADIOS);
586 return airplaneModeRadios == null
587 || airplaneModeRadios.contains(Settings.Global.RADIO_CELL);
588 }
589
590 private void setRadioPowerOff(Context context) {
591 Log.i(LOG_TAG, "Turning radio off - airplane");
592 Settings.Global.putInt(context.getContentResolver(), Settings.Global.CELL_ON,
593 PhoneConstants.CELL_OFF_DUE_TO_AIRPLANE_MODE_FLAG);
Sooraj Sasindran798bafa2017-04-03 22:49:00 -0700594 SystemProperties.set("persist.radio.airplane_mode_on", "1");
Chris Mantona09f3632016-02-09 14:48:42 -0800595 Settings.Global.putInt(getContentResolver(), Settings.Global.ENABLE_CELLULAR_ON_BOOT, 0);
596 PhoneUtils.setRadioPower(false);
597 }
598
599 private void setRadioPowerOn(Context context) {
600 Log.i(LOG_TAG, "Turning radio on - airplane");
601 Settings.Global.putInt(context.getContentResolver(), Settings.Global.CELL_ON,
602 PhoneConstants.CELL_ON_FLAG);
603 Settings.Global.putInt(getContentResolver(), Settings.Global.ENABLE_CELLULAR_ON_BOOT,
604 1);
Sooraj Sasindran798bafa2017-04-03 22:49:00 -0700605 SystemProperties.set("persist.radio.airplane_mode_on", "0");
Chris Mantona09f3632016-02-09 14:48:42 -0800606 PhoneUtils.setRadioPower(true);
607 }
608
609 private void maybeTurnCellOff(Context context, boolean isAirplaneNewlyOn) {
610 if (isAirplaneNewlyOn) {
Santos Cordone18902f2016-03-22 17:16:04 -0700611 // If we are trying to turn off the radio, make sure there are no active
612 // emergency calls. If there are, switch airplane mode back to off.
613 if (PhoneUtils.isInEmergencyCall(mCM)) {
614 // Switch airplane mode back to off.
615 ConnectivityManager.from(this).setAirplaneMode(false);
616 Toast.makeText(this, R.string.radio_off_during_emergency_call, Toast.LENGTH_LONG)
617 .show();
618 Log.i(LOG_TAG, "Ignoring airplane mode: emergency call. Turning airplane off");
Chris Mantona09f3632016-02-09 14:48:42 -0800619 } else if (isCellOffInAirplaneMode(context)) {
620 setRadioPowerOff(context);
Santos Cordone18902f2016-03-22 17:16:04 -0700621 } else {
Chris Mantona09f3632016-02-09 14:48:42 -0800622 Log.i(LOG_TAG, "Ignoring airplane mode: settings prevent cell radio power off");
Santos Cordone18902f2016-03-22 17:16:04 -0700623 }
Chris Mantona09f3632016-02-09 14:48:42 -0800624 }
625 }
626
627 private void maybeTurnCellOn(Context context, boolean isAirplaneNewlyOn) {
628 if (!isAirplaneNewlyOn) {
629 setRadioPowerOn(context);
Santos Cordone18902f2016-03-22 17:16:04 -0700630 }
631 }
632
Santos Cordon593ab382013-08-06 21:58:23 -0700633 /**
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700634 * Receiver for misc intent broadcasts the Phone app cares about.
635 */
636 private class PhoneAppBroadcastReceiver extends BroadcastReceiver {
637 @Override
638 public void onReceive(Context context, Intent intent) {
639 String action = intent.getAction();
640 if (action.equals(Intent.ACTION_AIRPLANE_MODE_CHANGED)) {
Santos Cordone18902f2016-03-22 17:16:04 -0700641 int airplaneMode = Settings.Global.getInt(getContentResolver(),
642 Settings.Global.AIRPLANE_MODE_ON, AIRPLANE_OFF);
643 // Treat any non-OFF values as ON.
644 if (airplaneMode != AIRPLANE_OFF) {
645 airplaneMode = AIRPLANE_ON;
646 }
Chris Mantona09f3632016-02-09 14:48:42 -0800647 handleAirplaneModeChange(context, airplaneMode);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700648 } else if (action.equals(TelephonyIntents.ACTION_ANY_DATA_CONNECTION_STATE_CHANGED)) {
Stuart Scottdcf40a92014-12-09 10:45:01 -0800649 int subId = intent.getIntExtra(PhoneConstants.SUBSCRIPTION_KEY,
650 SubscriptionManager.INVALID_SUBSCRIPTION_ID);
Jack Yu930a2512017-04-26 17:06:07 -0700651 final String apnType = intent.getStringExtra(PhoneConstants.DATA_APN_TYPE_KEY);
652 final String state = intent.getStringExtra(PhoneConstants.STATE_KEY);
653 final String reason = intent.getStringExtra(PhoneConstants.STATE_CHANGE_REASON_KEY);
Stuart Scottdcf40a92014-12-09 10:45:01 -0800654 if (VDBG) {
655 Log.d(LOG_TAG, "mReceiver: ACTION_ANY_DATA_CONNECTION_STATE_CHANGED");
656 Log.d(LOG_TAG, "- state: " + state);
Jack Yu930a2512017-04-26 17:06:07 -0700657 Log.d(LOG_TAG, "- reason: " + reason);
Stuart Scottdcf40a92014-12-09 10:45:01 -0800658 Log.d(LOG_TAG, "- subId: " + subId);
Stuart Scottdcf40a92014-12-09 10:45:01 -0800659 }
Santos Cordonc593d002015-06-03 15:41:15 -0700660
Jack Yu930a2512017-04-26 17:06:07 -0700661 // If the apn type of data connection state changed event is NOT default,
662 // ignore the broadcast intent and avoid action.
663 if (!PhoneConstants.APN_TYPE_DEFAULT.equals(apnType)) {
664 if (VDBG) Log.d(LOG_TAG, "Ignore broadcast intent as not default apn type");
Honggang0a05b652015-09-08 10:48:30 +0800665 return;
666 }
Jack Yu930a2512017-04-26 17:06:07 -0700667
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700668 // The "data disconnected due to roaming" notification is shown
669 // if (a) you have the "data roaming" feature turned off, and
670 // (b) you just lost data connectivity because you're roaming.
Jack Yu930a2512017-04-26 17:06:07 -0700671 if (PhoneConstants.DataState.DISCONNECTED.name().equals(state)
672 && Phone.REASON_ROAMING_ON.equals(reason)
673 && !getPhone(subId).getDataRoamingEnabled()) {
674 // Notify the user that data call is disconnected due to roaming. Note that
675 // calling this multiple times will not cause multiple notifications.
676 mHandler.sendEmptyMessage(EVENT_DATA_ROAMING_DISCONNECTED);
677 } else if (PhoneConstants.DataState.CONNECTED.name().equals(state)) {
678 // Cancel the notification when data is available. Note it is okay to call this
679 // even if the notification doesn't exist.
680 mHandler.sendEmptyMessage(EVENT_DATA_ROAMING_OK);
Yorke Lee4d2db1c2014-11-06 11:37:09 -0800681 }
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700682 } else if ((action.equals(TelephonyIntents.ACTION_SIM_STATE_CHANGED)) &&
683 (mPUKEntryActivity != null)) {
684 // if an attempt to un-PUK-lock the device was made, while we're
685 // receiving this state change notification, notify the handler.
686 // NOTE: This is ONLY triggered if an attempt to un-PUK-lock has
687 // been attempted.
688 mHandler.sendMessage(mHandler.obtainMessage(EVENT_SIM_STATE_CHANGED,
689 intent.getStringExtra(IccCardConstants.INTENT_KEY_ICC_STATE)));
690 } else if (action.equals(TelephonyIntents.ACTION_RADIO_TECHNOLOGY_CHANGED)) {
691 String newPhone = intent.getStringExtra(PhoneConstants.PHONE_NAME_KEY);
fionaxu80126972017-02-01 17:01:26 -0800692 Log.d(LOG_TAG, "Radio technology switched. Now " + newPhone + " is active.");
693 initForNewRadioTechnology();
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700694 } else if (action.equals(TelephonyIntents.ACTION_SERVICE_STATE_CHANGED)) {
695 handleServiceStateChanged(intent);
696 } else if (action.equals(TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED)) {
Sandeep Kuntade73a6a2014-10-15 18:45:56 +0530697 int phoneId = intent.getIntExtra(PhoneConstants.PHONE_KEY, 0);
Srikanth Chintala079912a2016-03-03 16:35:01 +0530698 phoneInEcm = PhoneFactory.getPhone(phoneId);
Sandeep Kuntade73a6a2014-10-15 18:45:56 +0530699 Log.d(LOG_TAG, "Emergency Callback Mode. phoneId:" + phoneId);
700 if (phoneInEcm != null) {
701 if (TelephonyCapabilities.supportsEcm(phoneInEcm)) {
702 Log.d(LOG_TAG, "Emergency Callback Mode arrived in PhoneApp.");
703 // Start Emergency Callback Mode service
704 if (intent.getBooleanExtra("phoneinECMState", false)) {
705 context.startService(new Intent(context,
706 EmergencyCallbackModeService.class));
707 } else {
708 phoneInEcm = null;
709 }
710 } else {
711 // It doesn't make sense to get ACTION_EMERGENCY_CALLBACK_MODE_CHANGED
712 // on a device that doesn't support ECM in the first place.
713 Log.e(LOG_TAG, "Got ACTION_EMERGENCY_CALLBACK_MODE_CHANGED, but "
714 + "ECM isn't supported for phone: " + phoneInEcm.getPhoneName());
715 phoneInEcm = null;
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700716 }
717 } else {
Sandeep Kuntade73a6a2014-10-15 18:45:56 +0530718 Log.w(LOG_TAG, "phoneInEcm is null.");
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700719 }
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700720 }
721 }
722 }
723
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700724 private void handleServiceStateChanged(Intent intent) {
725 /**
726 * This used to handle updating EriTextWidgetProvider this routine
727 * and and listening for ACTION_SERVICE_STATE_CHANGED intents could
728 * be removed. But leaving just in case it might be needed in the near
729 * future.
730 */
731
732 // If service just returned, start sending out the queued messages
Santos Cordonc593d002015-06-03 15:41:15 -0700733 Bundle extras = intent.getExtras();
734 if (extras != null) {
735 ServiceState ss = ServiceState.newFromBundle(extras);
736 if (ss != null) {
737 int state = ss.getState();
738 notificationMgr.updateNetworkSelection(state);
739 }
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700740 }
741 }
742
Sandeep Kuntade73a6a2014-10-15 18:45:56 +0530743 public Phone getPhoneInEcm() {
744 return phoneInEcm;
745 }
746
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700747 /**
Tyler Gunn9c1071f2014-12-09 10:07:54 -0800748 * Triggers a refresh of the message waiting (voicemail) indicator.
749 *
750 * @param subId the subscription id we should refresh the notification for.
751 */
752 public void refreshMwiIndicator(int subId) {
753 notificationMgr.refreshMwi(subId);
754 }
755
756 /**
Nancy Chenbb49d412015-07-23 13:54:16 -0700757 * Dismisses the message waiting (voicemail) indicator.
758 *
759 * @param subId the subscription id we should dismiss the notification for.
760 */
761 public void clearMwiIndicator(int subId) {
Ta-wei Yen63106682016-07-11 14:11:27 -0700762 // Setting voiceMessageCount to 0 will remove the current notification and clear the system
763 // cached value.
Ta-wei Yen7df340d2016-07-25 10:59:53 -0700764 Phone phone = getPhone(subId);
765 if (phone == null) {
766 Log.w(LOG_TAG, "clearMwiIndicator on null phone, subId:" + subId);
767 } else {
768 phone.setVoiceMessageCount(0);
769 }
Nancy Chenbb49d412015-07-23 13:54:16 -0700770 }
Ta-wei Yenb29425b2016-09-21 17:28:14 -0700771
772 /**
773 * Enables or disables the visual voicemail check for message waiting indicator. Default value
774 * is true. MWI is the traditional voicemail notification which should be suppressed if visual
775 * voicemail is active. {@link NotificationMgr#updateMwi(int, boolean, boolean)} currently
776 * checks the {@link android.provider.VoicemailContract.Status#CONFIGURATION_STATE} to suppress
777 * the MWI, but there are several issues. b/31229016 is a bug that when the device boots the
778 * configuration state will be cleared and the MWI for voicemail that arrives when the device
779 * is offline will be cleared, even if the account cannot be activated. A full solution will be
780 * adding a setMwiEnabled() method and stop checking the configuration state, but that is too
781 * risky at this moment. This is a temporary workaround to shut down the configuration state
782 * check if visual voicemail cannot be activated.
783 * <p>TODO(twyen): implement the setMwiEnabled() mentioned above.
784 *
785 * @param subId the account to set the enabled state
786 */
787 public void setShouldCheckVisualVoicemailConfigurationForMwi(int subId, boolean enabled) {
788 notificationMgr.setShouldCheckVisualVoicemailConfigurationForMwi(subId, enabled);
789 }
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700790}