blob: a73be65808886c357f34d4a2d613df92e57ab551 [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
Yorke Lee4d2db1c2014-11-06 11:37:09 -0800148 private boolean mDataDisconnectedDueToRoaming = false;
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700149
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700150 private WakeState mWakeState = WakeState.SLEEP;
151
152 private PowerManager mPowerManager;
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700153 private PowerManager.WakeLock mWakeLock;
154 private PowerManager.WakeLock mPartialWakeLock;
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700155 private KeyguardManager mKeyguardManager;
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700156
157 private UpdateLock mUpdateLock;
158
159 // Broadcast receiver for various intent broadcasts (see onCreate())
160 private final BroadcastReceiver mReceiver = new PhoneAppBroadcastReceiver();
161
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700162 Handler mHandler = new Handler() {
163 @Override
164 public void handleMessage(Message msg) {
165 PhoneConstants.State phoneState;
166 switch (msg.what) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700167 // TODO: This event should be handled by the lock screen, just
168 // like the "SIM missing" and "Sim locked" cases (bug 1804111).
169 case EVENT_SIM_NETWORK_LOCKED:
Jonathan Basseri9504c6b2015-06-04 14:23:32 -0700170 if (getCarrierConfig().getBoolean(
171 CarrierConfigManager.KEY_IGNORE_SIM_NETWORK_LOCKED_EVENTS_BOOL)) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700172 // Some products don't have the concept of a "SIM network lock"
173 Log.i(LOG_TAG, "Ignoring EVENT_SIM_NETWORK_LOCKED event; "
174 + "not showing 'SIM network unlock' PIN entry screen");
175 } else {
176 // Normal case: show the "SIM network unlock" PIN entry screen.
177 // The user won't be able to do anything else until
178 // they enter a valid SIM network PIN.
179 Log.i(LOG_TAG, "show sim depersonal panel");
Tyler Gunn52a37072015-08-24 14:23:19 -0700180 IccNetworkDepersonalizationPanel.showDialog();
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700181 }
182 break;
183
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700184 case EVENT_DATA_ROAMING_DISCONNECTED:
185 notificationMgr.showDataDisconnectedRoaming();
186 break;
187
188 case EVENT_DATA_ROAMING_OK:
189 notificationMgr.hideDataDisconnectedRoaming();
190 break;
191
192 case MMI_COMPLETE:
193 onMMIComplete((AsyncResult) msg.obj);
194 break;
195
196 case MMI_CANCEL:
Stuart Scottdcf40a92014-12-09 10:45:01 -0800197 PhoneUtils.cancelMmiCode(mCM.getFgPhone());
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700198 break;
199
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700200 case EVENT_SIM_STATE_CHANGED:
201 // Marks the event where the SIM goes into ready state.
202 // Right now, this is only used for the PUK-unlocking
203 // process.
204 if (msg.obj.equals(IccCardConstants.INTENT_VALUE_ICC_READY)) {
205 // when the right event is triggered and there
206 // are UI objects in the foreground, we close
207 // them to display the lock panel.
208 if (mPUKEntryActivity != null) {
209 mPUKEntryActivity.finish();
210 mPUKEntryActivity = null;
211 }
212 if (mPUKEntryProgressDialog != null) {
213 mPUKEntryProgressDialog.dismiss();
214 mPUKEntryProgressDialog = null;
215 }
216 }
217 break;
218
219 case EVENT_UNSOL_CDMA_INFO_RECORD:
220 //TODO: handle message here;
221 break;
Brad Ebinger3fa43462016-04-12 16:06:48 -0700222 case EVENT_RESTART_SIP:
223 // This should only run if the Phone process crashed and was restarted. We do
224 // not want this running if the device is still in the FBE encrypted state.
225 // This is the same procedure that is triggered in the SipBroadcastReceiver
226 // upon BOOT_COMPLETED.
227 UserManager userManager = UserManager.get(sMe);
228 if (userManager != null && userManager.isUserUnlocked()) {
229 SipUtil.startSipService();
230 }
231 break;
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700232 }
233 }
234 };
235
236 public PhoneGlobals(Context context) {
237 super(context);
238 sMe = this;
239 }
240
241 public void onCreate() {
242 if (VDBG) Log.v(LOG_TAG, "onCreate()...");
243
244 ContentResolver resolver = getContentResolver();
245
246 // Cache the "voice capable" flag.
247 // This flag currently comes from a resource (which is
248 // overrideable on a per-product basis):
249 sVoiceCapable =
250 getResources().getBoolean(com.android.internal.R.bool.config_voice_capable);
251 // ...but this might eventually become a PackageManager "system
252 // feature" instead, in which case we'd do something like:
253 // sVoiceCapable =
254 // getPackageManager().hasSystemFeature(PackageManager.FEATURE_TELEPHONY_VOICE_CALLS);
255
Stuart Scottdcf40a92014-12-09 10:45:01 -0800256 if (mCM == null) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700257 // Initialize the telephony framework
258 PhoneFactory.makeDefaultPhones(this);
259
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700260 // Start TelephonyDebugService After the default phone is created.
261 Intent intent = new Intent(this, TelephonyDebugService.class);
262 startService(intent);
263
264 mCM = CallManager.getInstance();
Stuart Scottdcf40a92014-12-09 10:45:01 -0800265 for (Phone phone : PhoneFactory.getPhones()) {
266 mCM.registerPhone(phone);
Stuart Scottdcf40a92014-12-09 10:45:01 -0800267 }
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700268
269 // Create the NotificationMgr singleton, which is used to display
270 // status bar icons and control other status bar behavior.
271 notificationMgr = NotificationMgr.init(this);
272
Brad Ebinger3fa43462016-04-12 16:06:48 -0700273 // If PhoneGlobals has crashed and is being restarted, then restart.
274 mHandler.sendEmptyMessage(EVENT_RESTART_SIP);
275
Anthony Lee03ebdfc2015-07-27 08:12:02 -0700276 // Create an instance of CdmaPhoneCallState and initialize it to IDLE
277 cdmaPhoneCallState = new CdmaPhoneCallState();
278 cdmaPhoneCallState.CdmaPhoneCallStateInit();
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700279
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700280 // before registering for phone state changes
281 mPowerManager = (PowerManager) getSystemService(Context.POWER_SERVICE);
282 mWakeLock = mPowerManager.newWakeLock(PowerManager.FULL_WAKE_LOCK, LOG_TAG);
283 // lock used to keep the processor awake, when we don't care for the display.
284 mPartialWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK
285 | PowerManager.ON_AFTER_RELEASE, LOG_TAG);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700286
287 mKeyguardManager = (KeyguardManager) getSystemService(Context.KEYGUARD_SERVICE);
288
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700289 // Get UpdateLock to suppress system-update related events (e.g. dialog show-up)
290 // during phone calls.
291 mUpdateLock = new UpdateLock("phone");
292
293 if (DBG) Log.d(LOG_TAG, "onCreate: mUpdateLock: " + mUpdateLock);
294
295 CallLogger callLogger = new CallLogger(this, new CallLogAsync());
296
Jay Shrauner21a75342013-11-25 16:14:43 -0800297 callGatewayManager = CallGatewayManager.getInstance();
Santos Cordon69a69192013-08-22 14:25:42 -0700298
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700299 // Create the CallController singleton, which is the interface
300 // to the telephony layer for user-initiated telephony functionality
301 // (like making outgoing calls.)
Santos Cordon69a69192013-08-22 14:25:42 -0700302 callController = CallController.init(this, callLogger, callGatewayManager);
303
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700304 // Create the CallerInfoCache singleton, which remembers custom ring tone and
305 // send-to-voicemail settings.
306 //
307 // The asynchronous caching will start just after this call.
308 callerInfoCache = CallerInfoCache.init(this);
309
Stuart Scottdcf40a92014-12-09 10:45:01 -0800310 phoneMgr = PhoneInterfaceManager.init(this, PhoneFactory.getDefaultPhone());
Santos Cordon406c0342013-08-28 00:07:47 -0700311
Jonathan Basseri6465afd2015-02-25 13:05:57 -0800312 configLoader = CarrierConfigLoader.init(this);
313
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700314 // Create the CallNotifer singleton, which handles
315 // asynchronous events from the telephony layer (like
316 // launching the incoming-call UI when an incoming call comes
317 // in.)
Brad Ebingera9c6b6d2016-01-07 17:24:16 -0800318 notifier = CallNotifier.init(this);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700319
Stuart Scottdcf40a92014-12-09 10:45:01 -0800320 PhoneUtils.registerIccStatus(mHandler, EVENT_SIM_NETWORK_LOCKED);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700321
322 // register for MMI/USSD
323 mCM.registerForMmiComplete(mHandler, MMI_COMPLETE, null);
324
325 // register connection tracking to PhoneUtils
326 PhoneUtils.initializeConnectionHandler(mCM);
327
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700328 // Register for misc other intent broadcasts.
329 IntentFilter intentFilter =
330 new IntentFilter(Intent.ACTION_AIRPLANE_MODE_CHANGED);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700331 intentFilter.addAction(TelephonyIntents.ACTION_ANY_DATA_CONNECTION_STATE_CHANGED);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700332 intentFilter.addAction(TelephonyIntents.ACTION_SIM_STATE_CHANGED);
333 intentFilter.addAction(TelephonyIntents.ACTION_RADIO_TECHNOLOGY_CHANGED);
334 intentFilter.addAction(TelephonyIntents.ACTION_SERVICE_STATE_CHANGED);
335 intentFilter.addAction(TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700336 registerReceiver(mReceiver, intentFilter);
337
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700338 //set the default values for the preferences in the phone.
pkanward702e542017-02-08 15:44:54 -0800339 PreferenceManager.setDefaultValues(this, R.xml.network_setting_fragment, false);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700340
341 PreferenceManager.setDefaultValues(this, R.xml.call_feature_setting, false);
342
343 // Make sure the audio mode (along with some
344 // audio-mode-related state of our own) is initialized
345 // correctly, given the current state of the phone.
346 PhoneUtils.setAudioMode(mCM);
347 }
348
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700349 // XXX pre-load the SimProvider so that it's ready
350 resolver.getType(Uri.parse("content://icc/adn"));
351
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700352 // TODO: Register for Cdma Information Records
353 // phone.registerCdmaInformationRecord(mHandler, EVENT_UNSOL_CDMA_INFO_RECORD, null);
354
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700355 // Read HAC settings and configure audio hardware
356 if (getResources().getBoolean(R.bool.hac_enabled)) {
Stuart Scottdcf40a92014-12-09 10:45:01 -0800357 int hac = android.provider.Settings.System.getInt(
358 getContentResolver(),
359 android.provider.Settings.System.HEARING_AID,
360 0);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700361 AudioManager audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
Andrew Leefb7f92e2015-02-26 16:23:32 -0800362 audioManager.setParameter(SettingsConstants.HAC_KEY,
363 hac == SettingsConstants.HAC_ENABLED
364 ? SettingsConstants.HAC_VAL_ON : SettingsConstants.HAC_VAL_OFF);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700365 }
Santos Cordonff506f52013-11-21 19:13:19 -0800366 }
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700367
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700368 /**
369 * Returns the singleton instance of the PhoneApp.
370 */
Sailesh Nepal1eaf22b2014-02-22 17:00:49 -0800371 public static PhoneGlobals getInstance() {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700372 if (sMe == null) {
373 throw new IllegalStateException("No PhoneGlobals here!");
374 }
375 return sMe;
376 }
377
378 /**
379 * Returns the singleton instance of the PhoneApp if running as the
380 * primary user, otherwise null.
381 */
382 static PhoneGlobals getInstanceIfPrimary() {
383 return sMe;
384 }
385
386 /**
Stuart Scottdcf40a92014-12-09 10:45:01 -0800387 * Returns the default phone.
388 *
Andrew Lee385019f2014-11-24 14:19:50 -0800389 * WARNING: This method should be used carefully, now that there may be multiple phones.
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700390 */
Andrew Lee83383e42014-10-31 12:42:28 -0700391 public static Phone getPhone() {
Stuart Scottdcf40a92014-12-09 10:45:01 -0800392 return PhoneFactory.getDefaultPhone();
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700393 }
394
Andrew Lee2fcb6c32014-12-04 14:52:35 -0800395 public static Phone getPhone(int subId) {
396 return PhoneFactory.getPhone(SubscriptionManager.getPhoneId(subId));
Andrew Lee385019f2014-11-24 14:19:50 -0800397 }
398
Santos Cordonde10b752013-09-19 04:11:33 -0700399 /* package */ CallManager getCallManager() {
400 return mCM;
401 }
402
Chris Manton4e9fa912015-06-19 11:26:57 -0700403 public PersistableBundle getCarrierConfig() {
Shishir Agrawald3480e02016-01-25 13:05:49 -0800404 return getCarrierConfigForSubId(SubscriptionManager.getDefaultSubscriptionId());
Jonathan Basseri89b0ab42015-05-01 10:52:40 -0700405 }
406
Chris Manton4e9fa912015-06-19 11:26:57 -0700407 public PersistableBundle getCarrierConfigForSubId(int subId) {
Jonathan Basseri89b0ab42015-05-01 10:52:40 -0700408 return configLoader.getConfigForSubId(subId);
Junda Liu605148f2015-04-28 15:23:40 -0700409 }
410
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700411 /**
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700412 * Sets the activity responsible for un-PUK-blocking the device
413 * so that we may close it when we receive a positive result.
414 * mPUKEntryActivity is also used to indicate to the device that
415 * we are trying to un-PUK-lock the phone. In other words, iff
416 * it is NOT null, then we are trying to unlock and waiting for
417 * the SIM to move to READY state.
418 *
419 * @param activity is the activity to close when PUK has
420 * finished unlocking. Can be set to null to indicate the unlock
421 * or SIM READYing process is over.
422 */
423 void setPukEntryActivity(Activity activity) {
424 mPUKEntryActivity = activity;
425 }
426
427 Activity getPUKEntryActivity() {
428 return mPUKEntryActivity;
429 }
430
431 /**
432 * Sets the dialog responsible for notifying the user of un-PUK-
433 * blocking - SIM READYing progress, so that we may dismiss it
434 * when we receive a positive result.
435 *
436 * @param dialog indicates the progress dialog informing the user
437 * of the state of the device. Dismissed upon completion of
438 * READYing process
439 */
440 void setPukEntryProgressDialog(ProgressDialog dialog) {
441 mPUKEntryProgressDialog = dialog;
442 }
443
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700444 /**
445 * Controls whether or not the screen is allowed to sleep.
446 *
447 * Once sleep is allowed (WakeState is SLEEP), it will rely on the
448 * settings for the poke lock to determine when to timeout and let
449 * the device sleep {@link PhoneGlobals#setScreenTimeout}.
450 *
451 * @param ws tells the device to how to wake.
452 */
453 /* package */ void requestWakeState(WakeState ws) {
454 if (VDBG) Log.d(LOG_TAG, "requestWakeState(" + ws + ")...");
455 synchronized (this) {
456 if (mWakeState != ws) {
457 switch (ws) {
458 case PARTIAL:
459 // acquire the processor wake lock, and release the FULL
460 // lock if it is being held.
461 mPartialWakeLock.acquire();
462 if (mWakeLock.isHeld()) {
463 mWakeLock.release();
464 }
465 break;
466 case FULL:
467 // acquire the full wake lock, and release the PARTIAL
468 // lock if it is being held.
469 mWakeLock.acquire();
470 if (mPartialWakeLock.isHeld()) {
471 mPartialWakeLock.release();
472 }
473 break;
474 case SLEEP:
475 default:
476 // release both the PARTIAL and FULL locks.
477 if (mWakeLock.isHeld()) {
478 mWakeLock.release();
479 }
480 if (mPartialWakeLock.isHeld()) {
481 mPartialWakeLock.release();
482 }
483 break;
484 }
485 mWakeState = ws;
486 }
487 }
488 }
489
490 /**
491 * If we are not currently keeping the screen on, then poke the power
492 * manager to wake up the screen for the user activity timeout duration.
493 */
494 /* package */ void wakeUpScreen() {
495 synchronized (this) {
496 if (mWakeState == WakeState.SLEEP) {
497 if (DBG) Log.d(LOG_TAG, "pulse screen lock");
Dianne Hackborn148769b2015-07-13 17:55:47 -0700498 mPowerManager.wakeUp(SystemClock.uptimeMillis(), "android.phone:WAKE");
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700499 }
500 }
501 }
502
503 /**
504 * Sets the wake state and screen timeout based on the current state
505 * of the phone, and the current state of the in-call UI.
506 *
507 * This method is a "UI Policy" wrapper around
508 * {@link PhoneGlobals#requestWakeState} and {@link PhoneGlobals#setScreenTimeout}.
509 *
510 * It's safe to call this method regardless of the state of the Phone
511 * (e.g. whether or not it's idle), and regardless of the state of the
512 * Phone UI (e.g. whether or not the InCallScreen is active.)
513 */
514 /* package */ void updateWakeState() {
515 PhoneConstants.State state = mCM.getState();
516
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700517 // True if the speakerphone is in use. (If so, we *always* use
518 // the default timeout. Since the user is obviously not holding
519 // the phone up to his/her face, we don't need to worry about
520 // false touches, and thus don't need to turn the screen off so
521 // aggressively.)
522 // Note that we need to make a fresh call to this method any
523 // time the speaker state changes. (That happens in
524 // PhoneUtils.turnOnSpeaker().)
525 boolean isSpeakerInUse = (state == PhoneConstants.State.OFFHOOK) && PhoneUtils.isSpeakerOn(this);
526
527 // TODO (bug 1440854): The screen timeout *might* also need to
528 // depend on the bluetooth state, but this isn't as clear-cut as
529 // the speaker state (since while using BT it's common for the
530 // user to put the phone straight into a pocket, in which case the
531 // timeout should probably still be short.)
532
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700533 // Decide whether to force the screen on or not.
534 //
535 // Force the screen to be on if the phone is ringing or dialing,
536 // or if we're displaying the "Call ended" UI for a connection in
537 // the "disconnected" state.
538 // However, if the phone is disconnected while the user is in the
539 // middle of selecting a quick response message, we should not force
540 // the screen to be on.
541 //
542 boolean isRinging = (state == PhoneConstants.State.RINGING);
Stuart Scottdcf40a92014-12-09 10:45:01 -0800543 boolean isDialing = (mCM.getFgPhone().getForegroundCall().getState() == Call.State.DIALING);
Jay Shrauner6fe8fd62013-09-16 19:39:30 -0700544 boolean keepScreenOn = isRinging || isDialing;
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700545 // keepScreenOn == true means we'll hold a full wake lock:
546 requestWakeState(keepScreenOn ? WakeState.FULL : WakeState.SLEEP);
547 }
548
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700549 KeyguardManager getKeyguardManager() {
550 return mKeyguardManager;
551 }
552
553 private void onMMIComplete(AsyncResult r) {
554 if (VDBG) Log.d(LOG_TAG, "onMMIComplete()...");
555 MmiCode mmiCode = (MmiCode) r.result;
Stuart Scottdcf40a92014-12-09 10:45:01 -0800556 PhoneUtils.displayMMIComplete(mmiCode.getPhone(), getInstance(), mmiCode, null, null);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700557 }
558
fionaxu80126972017-02-01 17:01:26 -0800559 private void initForNewRadioTechnology() {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700560 if (DBG) Log.d(LOG_TAG, "initForNewRadioTechnology...");
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700561 notifier.updateCallNotifierRegistrationsAfterRadioTechnologyChange();
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700562 }
563
Chris Mantona09f3632016-02-09 14:48:42 -0800564 private void handleAirplaneModeChange(Context context, int newMode) {
565 int cellState = Settings.Global.getInt(context.getContentResolver(),
566 Settings.Global.CELL_ON, PhoneConstants.CELL_ON_FLAG);
567 boolean isAirplaneNewlyOn = (newMode == 1);
568 switch (cellState) {
569 case PhoneConstants.CELL_OFF_FLAG:
570 // Airplane mode does not affect the cell radio if user
571 // has turned it off.
572 break;
573 case PhoneConstants.CELL_ON_FLAG:
574 maybeTurnCellOff(context, isAirplaneNewlyOn);
575 break;
576 case PhoneConstants.CELL_OFF_DUE_TO_AIRPLANE_MODE_FLAG:
577 maybeTurnCellOn(context, isAirplaneNewlyOn);
578 break;
579 }
580 }
581
582 /*
583 * Returns true if the radio must be turned off when entering airplane mode.
584 */
585 private boolean isCellOffInAirplaneMode(Context context) {
586 String airplaneModeRadios = Settings.Global.getString(context.getContentResolver(),
587 Settings.Global.AIRPLANE_MODE_RADIOS);
588 return airplaneModeRadios == null
589 || airplaneModeRadios.contains(Settings.Global.RADIO_CELL);
590 }
591
592 private void setRadioPowerOff(Context context) {
593 Log.i(LOG_TAG, "Turning radio off - airplane");
594 Settings.Global.putInt(context.getContentResolver(), Settings.Global.CELL_ON,
595 PhoneConstants.CELL_OFF_DUE_TO_AIRPLANE_MODE_FLAG);
Sooraj Sasindran798bafa2017-04-03 22:49:00 -0700596 SystemProperties.set("persist.radio.airplane_mode_on", "1");
Chris Mantona09f3632016-02-09 14:48:42 -0800597 Settings.Global.putInt(getContentResolver(), Settings.Global.ENABLE_CELLULAR_ON_BOOT, 0);
598 PhoneUtils.setRadioPower(false);
599 }
600
601 private void setRadioPowerOn(Context context) {
602 Log.i(LOG_TAG, "Turning radio on - airplane");
603 Settings.Global.putInt(context.getContentResolver(), Settings.Global.CELL_ON,
604 PhoneConstants.CELL_ON_FLAG);
605 Settings.Global.putInt(getContentResolver(), Settings.Global.ENABLE_CELLULAR_ON_BOOT,
606 1);
Sooraj Sasindran798bafa2017-04-03 22:49:00 -0700607 SystemProperties.set("persist.radio.airplane_mode_on", "0");
Chris Mantona09f3632016-02-09 14:48:42 -0800608 PhoneUtils.setRadioPower(true);
609 }
610
611 private void maybeTurnCellOff(Context context, boolean isAirplaneNewlyOn) {
612 if (isAirplaneNewlyOn) {
Santos Cordone18902f2016-03-22 17:16:04 -0700613 // If we are trying to turn off the radio, make sure there are no active
614 // emergency calls. If there are, switch airplane mode back to off.
615 if (PhoneUtils.isInEmergencyCall(mCM)) {
616 // Switch airplane mode back to off.
617 ConnectivityManager.from(this).setAirplaneMode(false);
618 Toast.makeText(this, R.string.radio_off_during_emergency_call, Toast.LENGTH_LONG)
619 .show();
620 Log.i(LOG_TAG, "Ignoring airplane mode: emergency call. Turning airplane off");
Chris Mantona09f3632016-02-09 14:48:42 -0800621 } else if (isCellOffInAirplaneMode(context)) {
622 setRadioPowerOff(context);
Santos Cordone18902f2016-03-22 17:16:04 -0700623 } else {
Chris Mantona09f3632016-02-09 14:48:42 -0800624 Log.i(LOG_TAG, "Ignoring airplane mode: settings prevent cell radio power off");
Santos Cordone18902f2016-03-22 17:16:04 -0700625 }
Chris Mantona09f3632016-02-09 14:48:42 -0800626 }
627 }
628
629 private void maybeTurnCellOn(Context context, boolean isAirplaneNewlyOn) {
630 if (!isAirplaneNewlyOn) {
631 setRadioPowerOn(context);
Santos Cordone18902f2016-03-22 17:16:04 -0700632 }
633 }
634
Santos Cordon593ab382013-08-06 21:58:23 -0700635 /**
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700636 * Receiver for misc intent broadcasts the Phone app cares about.
637 */
638 private class PhoneAppBroadcastReceiver extends BroadcastReceiver {
639 @Override
640 public void onReceive(Context context, Intent intent) {
641 String action = intent.getAction();
642 if (action.equals(Intent.ACTION_AIRPLANE_MODE_CHANGED)) {
Santos Cordone18902f2016-03-22 17:16:04 -0700643 int airplaneMode = Settings.Global.getInt(getContentResolver(),
644 Settings.Global.AIRPLANE_MODE_ON, AIRPLANE_OFF);
645 // Treat any non-OFF values as ON.
646 if (airplaneMode != AIRPLANE_OFF) {
647 airplaneMode = AIRPLANE_ON;
648 }
Chris Mantona09f3632016-02-09 14:48:42 -0800649 handleAirplaneModeChange(context, airplaneMode);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700650 } else if (action.equals(TelephonyIntents.ACTION_ANY_DATA_CONNECTION_STATE_CHANGED)) {
Stuart Scottdcf40a92014-12-09 10:45:01 -0800651 int subId = intent.getIntExtra(PhoneConstants.SUBSCRIPTION_KEY,
652 SubscriptionManager.INVALID_SUBSCRIPTION_ID);
653 int phoneId = SubscriptionManager.getPhoneId(subId);
654 String state = intent.getStringExtra(PhoneConstants.STATE_KEY);
655 if (VDBG) {
656 Log.d(LOG_TAG, "mReceiver: ACTION_ANY_DATA_CONNECTION_STATE_CHANGED");
657 Log.d(LOG_TAG, "- state: " + state);
658 Log.d(LOG_TAG, "- reason: "
659 + intent.getStringExtra(PhoneConstants.STATE_CHANGE_REASON_KEY));
660 Log.d(LOG_TAG, "- subId: " + subId);
661 Log.d(LOG_TAG, "- phoneId: " + phoneId);
662 }
663 Phone phone = SubscriptionManager.isValidPhoneId(phoneId) ?
664 PhoneFactory.getPhone(phoneId) : PhoneFactory.getDefaultPhone();
Santos Cordonc593d002015-06-03 15:41:15 -0700665
Honggang0a05b652015-09-08 10:48:30 +0800666 // If not default data subscription, ignore the broadcast intent and avoid action.
Andreas Gampebab21c72016-07-19 13:54:25 -0700667 if (subId != SubscriptionManager.getDefaultDataSubscriptionId()) {
Honggang0a05b652015-09-08 10:48:30 +0800668 if (VDBG) Log.d(LOG_TAG, "Ignore broadcast intent as not default data sub.");
669 return;
670 }
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);
fionaxu80126972017-02-01 17:01:26 -0800694 Log.d(LOG_TAG, "Radio technology switched. Now " + newPhone + " is active.");
695 initForNewRadioTechnology();
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700696 } else if (action.equals(TelephonyIntents.ACTION_SERVICE_STATE_CHANGED)) {
697 handleServiceStateChanged(intent);
698 } else if (action.equals(TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED)) {
Sandeep Kuntade73a6a2014-10-15 18:45:56 +0530699 int phoneId = intent.getIntExtra(PhoneConstants.PHONE_KEY, 0);
Srikanth Chintala079912a2016-03-03 16:35:01 +0530700 phoneInEcm = PhoneFactory.getPhone(phoneId);
Sandeep Kuntade73a6a2014-10-15 18:45:56 +0530701 Log.d(LOG_TAG, "Emergency Callback Mode. phoneId:" + phoneId);
702 if (phoneInEcm != null) {
703 if (TelephonyCapabilities.supportsEcm(phoneInEcm)) {
704 Log.d(LOG_TAG, "Emergency Callback Mode arrived in PhoneApp.");
705 // Start Emergency Callback Mode service
706 if (intent.getBooleanExtra("phoneinECMState", false)) {
707 context.startService(new Intent(context,
708 EmergencyCallbackModeService.class));
709 } else {
710 phoneInEcm = null;
711 }
712 } else {
713 // It doesn't make sense to get ACTION_EMERGENCY_CALLBACK_MODE_CHANGED
714 // on a device that doesn't support ECM in the first place.
715 Log.e(LOG_TAG, "Got ACTION_EMERGENCY_CALLBACK_MODE_CHANGED, but "
716 + "ECM isn't supported for phone: " + phoneInEcm.getPhoneName());
717 phoneInEcm = null;
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700718 }
719 } else {
Sandeep Kuntade73a6a2014-10-15 18:45:56 +0530720 Log.w(LOG_TAG, "phoneInEcm is null.");
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700721 }
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700722 }
723 }
724 }
725
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700726 private void handleServiceStateChanged(Intent intent) {
727 /**
728 * This used to handle updating EriTextWidgetProvider this routine
729 * and and listening for ACTION_SERVICE_STATE_CHANGED intents could
730 * be removed. But leaving just in case it might be needed in the near
731 * future.
732 */
733
734 // If service just returned, start sending out the queued messages
Santos Cordonc593d002015-06-03 15:41:15 -0700735 Bundle extras = intent.getExtras();
736 if (extras != null) {
737 ServiceState ss = ServiceState.newFromBundle(extras);
738 if (ss != null) {
739 int state = ss.getState();
740 notificationMgr.updateNetworkSelection(state);
741 }
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700742 }
743 }
744
Sandeep Kuntade73a6a2014-10-15 18:45:56 +0530745 public Phone getPhoneInEcm() {
746 return phoneInEcm;
747 }
748
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700749 /**
Tyler Gunn9c1071f2014-12-09 10:07:54 -0800750 * Triggers a refresh of the message waiting (voicemail) indicator.
751 *
752 * @param subId the subscription id we should refresh the notification for.
753 */
754 public void refreshMwiIndicator(int subId) {
755 notificationMgr.refreshMwi(subId);
756 }
757
758 /**
Nancy Chenbb49d412015-07-23 13:54:16 -0700759 * Dismisses the message waiting (voicemail) indicator.
760 *
761 * @param subId the subscription id we should dismiss the notification for.
762 */
763 public void clearMwiIndicator(int subId) {
Ta-wei Yen63106682016-07-11 14:11:27 -0700764 // Setting voiceMessageCount to 0 will remove the current notification and clear the system
765 // cached value.
Ta-wei Yen7df340d2016-07-25 10:59:53 -0700766 Phone phone = getPhone(subId);
767 if (phone == null) {
768 Log.w(LOG_TAG, "clearMwiIndicator on null phone, subId:" + subId);
769 } else {
770 phone.setVoiceMessageCount(0);
771 }
Nancy Chenbb49d412015-07-23 13:54:16 -0700772 }
Ta-wei Yenb29425b2016-09-21 17:28:14 -0700773
774 /**
775 * Enables or disables the visual voicemail check for message waiting indicator. Default value
776 * is true. MWI is the traditional voicemail notification which should be suppressed if visual
777 * voicemail is active. {@link NotificationMgr#updateMwi(int, boolean, boolean)} currently
778 * checks the {@link android.provider.VoicemailContract.Status#CONFIGURATION_STATE} to suppress
779 * the MWI, but there are several issues. b/31229016 is a bug that when the device boots the
780 * configuration state will be cleared and the MWI for voicemail that arrives when the device
781 * is offline will be cleared, even if the account cannot be activated. A full solution will be
782 * adding a setMwiEnabled() method and stop checking the configuration state, but that is too
783 * risky at this moment. This is a temporary workaround to shut down the configuration state
784 * check if visual voicemail cannot be activated.
785 * <p>TODO(twyen): implement the setMwiEnabled() mentioned above.
786 *
787 * @param subId the account to set the enabled state
788 */
789 public void setShouldCheckVisualVoicemailConfigurationForMwi(int subId, boolean enabled) {
790 notificationMgr.setShouldCheckVisualVoicemailConfigurationForMwi(subId, enabled);
791 }
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700792}