blob: df2568455b01662d39e9b141f379977111c1a746 [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;
21import android.app.PendingIntent;
22import android.app.ProgressDialog;
Yorke Leeca6ec3b2013-08-29 14:21:43 -070023import android.app.TaskStackBuilder;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070024import android.bluetooth.BluetoothAdapter;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070025import android.bluetooth.IBluetoothHeadsetPhone;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070026import android.content.BroadcastReceiver;
27import android.content.ComponentName;
28import android.content.ContentResolver;
29import android.content.Context;
30import android.content.ContextWrapper;
31import android.content.Intent;
32import android.content.IntentFilter;
33import android.content.ServiceConnection;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070034import android.media.AudioManager;
35import android.net.Uri;
36import android.os.AsyncResult;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070037import android.os.Handler;
38import android.os.IBinder;
39import android.os.IPowerManager;
40import android.os.Message;
41import android.os.PowerManager;
42import android.os.RemoteException;
43import android.os.ServiceManager;
44import android.os.SystemClock;
45import android.os.SystemProperties;
46import android.os.UpdateLock;
47import android.os.UserHandle;
48import android.preference.PreferenceManager;
49import android.provider.Settings.System;
50import android.telephony.ServiceState;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070051import android.util.Log;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070052
53import com.android.internal.telephony.Call;
54import com.android.internal.telephony.CallManager;
55import com.android.internal.telephony.IccCard;
56import com.android.internal.telephony.IccCardConstants;
57import com.android.internal.telephony.MmiCode;
58import com.android.internal.telephony.Phone;
59import com.android.internal.telephony.PhoneConstants;
60import com.android.internal.telephony.PhoneFactory;
61import com.android.internal.telephony.TelephonyCapabilities;
62import com.android.internal.telephony.TelephonyIntents;
Santos Cordon593ab382013-08-06 21:58:23 -070063import com.android.phone.WiredHeadsetManager.WiredHeadsetListener;
Santos Cordon352ff652014-05-30 01:41:45 -070064import com.android.phone.common.CallLogAsync;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070065import com.android.server.sip.SipService;
66
67/**
68 * Global state for the telephony subsystem when running in the primary
69 * phone process.
70 */
Sailesh Nepalbf900542014-07-15 16:18:32 -070071public class PhoneGlobals extends ContextWrapper {
Santos Cordon7d4ddf62013-07-10 11:58:08 -070072 /* package */ static final String LOG_TAG = "PhoneApp";
73
74 /**
75 * Phone app-wide debug level:
76 * 0 - no debug logging
77 * 1 - normal debug logging if ro.debuggable is set (which is true in
78 * "eng" and "userdebug" builds but not "user" builds)
79 * 2 - ultra-verbose debug logging
80 *
81 * Most individual classes in the phone app have a local DBG constant,
82 * typically set to
83 * (PhoneApp.DBG_LEVEL >= 1) && (SystemProperties.getInt("ro.debuggable", 0) == 1)
84 * or else
85 * (PhoneApp.DBG_LEVEL >= 2)
86 * depending on the desired verbosity.
87 *
88 * ***** DO NOT SUBMIT WITH DBG_LEVEL > 0 *************
89 */
90 /* package */ static final int DBG_LEVEL = 0;
91
92 private static final boolean DBG =
93 (PhoneGlobals.DBG_LEVEL >= 1) && (SystemProperties.getInt("ro.debuggable", 0) == 1);
94 private static final boolean VDBG = (PhoneGlobals.DBG_LEVEL >= 2);
95
96 // Message codes; see mHandler below.
97 private static final int EVENT_SIM_NETWORK_LOCKED = 3;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070098 private static final int EVENT_SIM_STATE_CHANGED = 8;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070099 private static final int EVENT_DATA_ROAMING_DISCONNECTED = 10;
100 private static final int EVENT_DATA_ROAMING_OK = 11;
101 private static final int EVENT_UNSOL_CDMA_INFO_RECORD = 12;
102 private static final int EVENT_DOCK_STATE_CHANGED = 13;
Sailesh Nepalbf900542014-07-15 16:18:32 -0700103 private static final int EVENT_START_SIP_SERVICE = 14;
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700104
105 // The MMI codes are also used by the InCallScreen.
106 public static final int MMI_INITIATE = 51;
107 public static final int MMI_COMPLETE = 52;
108 public static final int MMI_CANCEL = 53;
109 // Don't use message codes larger than 99 here; those are reserved for
110 // the individual Activities of the Phone UI.
111
112 /**
113 * Allowable values for the wake lock code.
114 * SLEEP means the device can be put to sleep.
115 * PARTIAL means wake the processor, but we display can be kept off.
116 * FULL means wake both the processor and the display.
117 */
118 public enum WakeState {
119 SLEEP,
120 PARTIAL,
121 FULL
122 }
123
124 /**
125 * Intent Action used for hanging up the current call from Notification bar. This will
126 * choose first ringing call, first active call, or first background call (typically in
127 * HOLDING state).
128 */
129 public static final String ACTION_HANG_UP_ONGOING_CALL =
130 "com.android.phone.ACTION_HANG_UP_ONGOING_CALL";
131
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700132 private static PhoneGlobals sMe;
133
134 // A few important fields we expose to the rest of the package
135 // directly (rather than thru set/get methods) for efficiency.
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700136 CallController callController;
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700137 CallManager mCM;
Santos Cordon63a84242013-07-23 13:32:52 -0700138 CallNotifier notifier;
139 CallerInfoCache callerInfoCache;
Santos Cordon63a84242013-07-23 13:32:52 -0700140 NotificationMgr notificationMgr;
141 Phone phone;
142 PhoneInterfaceManager phoneMgr;
143
Santos Cordon9b7bac72013-08-06 08:04:52 -0700144 private AudioRouter audioRouter;
Santos Cordon27a3c1f2013-08-06 07:49:27 -0700145 private BluetoothManager bluetoothManager;
Santos Cordon69a69192013-08-22 14:25:42 -0700146 private CallGatewayManager callGatewayManager;
Santos Cordon63a84242013-07-23 13:32:52 -0700147 private CallStateMonitor callStateMonitor;
148 private IBluetoothHeadsetPhone mBluetoothPhone;
149 private Ringer ringer;
Santos Cordon593ab382013-08-06 21:58:23 -0700150 private WiredHeadsetManager wiredHeadsetManager;
Santos Cordon63a84242013-07-23 13:32:52 -0700151
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700152 static int mDockState = Intent.EXTRA_DOCK_STATE_UNDOCKED;
153 static boolean sVoiceCapable = true;
154
155 // Internal PhoneApp Call state tracker
156 CdmaPhoneCallState cdmaPhoneCallState;
157
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700158 // The currently-active PUK entry activity and progress dialog.
159 // Normally, these are the Emergency Dialer and the subsequent
160 // progress dialog. null if there is are no such objects in
161 // the foreground.
162 private Activity mPUKEntryActivity;
163 private ProgressDialog mPUKEntryProgressDialog;
164
165 private boolean mIsSimPinEnabled;
166 private String mCachedSimPin;
167
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700168 // True if we are beginning a call, but the phone state has not changed yet
169 private boolean mBeginningCall;
170
171 // Last phone state seen by updatePhoneState()
172 private PhoneConstants.State mLastPhoneState = PhoneConstants.State.IDLE;
173
174 private WakeState mWakeState = WakeState.SLEEP;
175
176 private PowerManager mPowerManager;
177 private IPowerManager mPowerManagerService;
178 private PowerManager.WakeLock mWakeLock;
179 private PowerManager.WakeLock mPartialWakeLock;
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700180 private KeyguardManager mKeyguardManager;
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700181
182 private UpdateLock mUpdateLock;
183
184 // Broadcast receiver for various intent broadcasts (see onCreate())
185 private final BroadcastReceiver mReceiver = new PhoneAppBroadcastReceiver();
186
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700187 /** boolean indicating restoring mute state on InCallScreen.onResume() */
188 private boolean mShouldRestoreMuteOnInCallResume;
189
190 /**
191 * The singleton OtaUtils instance used for OTASP calls.
192 *
193 * The OtaUtils instance is created lazily the first time we need to
194 * make an OTASP call, regardless of whether it's an interactive or
195 * non-interactive OTASP call.
196 */
197 public OtaUtils otaUtils;
198
199 // Following are the CDMA OTA information Objects used during OTA Call.
200 // cdmaOtaProvisionData object store static OTA information that needs
201 // to be maintained even during Slider open/close scenarios.
202 // cdmaOtaConfigData object stores configuration info to control visiblity
203 // of each OTA Screens.
204 // cdmaOtaScreenState object store OTA Screen State information.
205 public OtaUtils.CdmaOtaProvisionData cdmaOtaProvisionData;
206 public OtaUtils.CdmaOtaConfigData cdmaOtaConfigData;
207 public OtaUtils.CdmaOtaScreenState cdmaOtaScreenState;
208 public OtaUtils.CdmaOtaInCallScreenUiState cdmaOtaInCallScreenUiState;
209
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700210 /**
211 * Set the restore mute state flag. Used when we are setting the mute state
212 * OUTSIDE of user interaction {@link PhoneUtils#startNewCall(Phone)}
213 */
214 /*package*/void setRestoreMuteOnInCallResume (boolean mode) {
215 mShouldRestoreMuteOnInCallResume = mode;
216 }
217
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700218 Handler mHandler = new Handler() {
219 @Override
220 public void handleMessage(Message msg) {
221 PhoneConstants.State phoneState;
222 switch (msg.what) {
223 // Starts the SIP service. It's a no-op if SIP API is not supported
224 // on the deivce.
225 // TODO: Having the phone process host the SIP service is only
226 // temporary. Will move it to a persistent communication process
227 // later.
228 case EVENT_START_SIP_SERVICE:
229 SipService.start(getApplicationContext());
230 break;
231
232 // TODO: This event should be handled by the lock screen, just
233 // like the "SIM missing" and "Sim locked" cases (bug 1804111).
234 case EVENT_SIM_NETWORK_LOCKED:
235 if (getResources().getBoolean(R.bool.ignore_sim_network_locked_events)) {
236 // Some products don't have the concept of a "SIM network lock"
237 Log.i(LOG_TAG, "Ignoring EVENT_SIM_NETWORK_LOCKED event; "
238 + "not showing 'SIM network unlock' PIN entry screen");
239 } else {
240 // Normal case: show the "SIM network unlock" PIN entry screen.
241 // The user won't be able to do anything else until
242 // they enter a valid SIM network PIN.
243 Log.i(LOG_TAG, "show sim depersonal panel");
244 IccNetworkDepersonalizationPanel ndpPanel =
245 new IccNetworkDepersonalizationPanel(PhoneGlobals.getInstance());
246 ndpPanel.show();
247 }
248 break;
249
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700250 case EVENT_DATA_ROAMING_DISCONNECTED:
251 notificationMgr.showDataDisconnectedRoaming();
252 break;
253
254 case EVENT_DATA_ROAMING_OK:
255 notificationMgr.hideDataDisconnectedRoaming();
256 break;
257
258 case MMI_COMPLETE:
259 onMMIComplete((AsyncResult) msg.obj);
260 break;
261
262 case MMI_CANCEL:
263 PhoneUtils.cancelMmiCode(phone);
264 break;
265
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700266 case EVENT_SIM_STATE_CHANGED:
267 // Marks the event where the SIM goes into ready state.
268 // Right now, this is only used for the PUK-unlocking
269 // process.
270 if (msg.obj.equals(IccCardConstants.INTENT_VALUE_ICC_READY)) {
271 // when the right event is triggered and there
272 // are UI objects in the foreground, we close
273 // them to display the lock panel.
274 if (mPUKEntryActivity != null) {
275 mPUKEntryActivity.finish();
276 mPUKEntryActivity = null;
277 }
278 if (mPUKEntryProgressDialog != null) {
279 mPUKEntryProgressDialog.dismiss();
280 mPUKEntryProgressDialog = null;
281 }
282 }
283 break;
284
285 case EVENT_UNSOL_CDMA_INFO_RECORD:
286 //TODO: handle message here;
287 break;
288
289 case EVENT_DOCK_STATE_CHANGED:
290 // If the phone is docked/undocked during a call, and no wired or BT headset
291 // is connected: turn on/off the speaker accordingly.
292 boolean inDockMode = false;
293 if (mDockState != Intent.EXTRA_DOCK_STATE_UNDOCKED) {
294 inDockMode = true;
295 }
296 if (VDBG) Log.d(LOG_TAG, "received EVENT_DOCK_STATE_CHANGED. Phone inDock = "
297 + inDockMode);
298
299 phoneState = mCM.getState();
300 if (phoneState == PhoneConstants.State.OFFHOOK &&
Santos Cordon593ab382013-08-06 21:58:23 -0700301 !wiredHeadsetManager.isHeadsetPlugged() &&
302 !bluetoothManager.isBluetoothHeadsetAudioOn()) {
303 audioRouter.setSpeaker(inDockMode);
304
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700305 PhoneUtils.turnOnSpeaker(getApplicationContext(), inDockMode, true);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700306 }
307 break;
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700308 }
309 }
310 };
311
312 public PhoneGlobals(Context context) {
313 super(context);
314 sMe = this;
315 }
316
317 public void onCreate() {
318 if (VDBG) Log.v(LOG_TAG, "onCreate()...");
319
320 ContentResolver resolver = getContentResolver();
321
322 // Cache the "voice capable" flag.
323 // This flag currently comes from a resource (which is
324 // overrideable on a per-product basis):
325 sVoiceCapable =
326 getResources().getBoolean(com.android.internal.R.bool.config_voice_capable);
327 // ...but this might eventually become a PackageManager "system
328 // feature" instead, in which case we'd do something like:
329 // sVoiceCapable =
330 // getPackageManager().hasSystemFeature(PackageManager.FEATURE_TELEPHONY_VOICE_CALLS);
331
332 if (phone == null) {
333 // Initialize the telephony framework
334 PhoneFactory.makeDefaultPhones(this);
335
336 // Get the default phone
337 phone = PhoneFactory.getDefaultPhone();
338
339 // Start TelephonyDebugService After the default phone is created.
340 Intent intent = new Intent(this, TelephonyDebugService.class);
341 startService(intent);
342
343 mCM = CallManager.getInstance();
344 mCM.registerPhone(phone);
345
346 // Create the NotificationMgr singleton, which is used to display
347 // status bar icons and control other status bar behavior.
348 notificationMgr = NotificationMgr.init(this);
349
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700350 mHandler.sendEmptyMessage(EVENT_START_SIP_SERVICE);
351
352 int phoneType = phone.getPhoneType();
353
354 if (phoneType == PhoneConstants.PHONE_TYPE_CDMA) {
355 // Create an instance of CdmaPhoneCallState and initialize it to IDLE
356 cdmaPhoneCallState = new CdmaPhoneCallState();
357 cdmaPhoneCallState.CdmaPhoneCallStateInit();
358 }
359
360 if (BluetoothAdapter.getDefaultAdapter() != null) {
361 // Start BluetoothPhoneService even if device is not voice capable.
362 // The device can still support VOIP.
363 startService(new Intent(this, BluetoothPhoneService.class));
364 bindService(new Intent(this, BluetoothPhoneService.class),
365 mBluetoothPhoneConnection, 0);
366 } else {
367 // Device is not bluetooth capable
368 mBluetoothPhone = null;
369 }
370
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700371 // before registering for phone state changes
372 mPowerManager = (PowerManager) getSystemService(Context.POWER_SERVICE);
373 mWakeLock = mPowerManager.newWakeLock(PowerManager.FULL_WAKE_LOCK, LOG_TAG);
374 // lock used to keep the processor awake, when we don't care for the display.
375 mPartialWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK
376 | PowerManager.ON_AFTER_RELEASE, LOG_TAG);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700377
378 mKeyguardManager = (KeyguardManager) getSystemService(Context.KEYGUARD_SERVICE);
379
380 // get a handle to the service so that we can use it later when we
381 // want to set the poke lock.
382 mPowerManagerService = IPowerManager.Stub.asInterface(
383 ServiceManager.getService("power"));
384
385 // Get UpdateLock to suppress system-update related events (e.g. dialog show-up)
386 // during phone calls.
387 mUpdateLock = new UpdateLock("phone");
388
389 if (DBG) Log.d(LOG_TAG, "onCreate: mUpdateLock: " + mUpdateLock);
390
391 CallLogger callLogger = new CallLogger(this, new CallLogAsync());
392
Jay Shrauner21a75342013-11-25 16:14:43 -0800393 callGatewayManager = CallGatewayManager.getInstance();
Santos Cordon69a69192013-08-22 14:25:42 -0700394
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700395 // Create the CallController singleton, which is the interface
396 // to the telephony layer for user-initiated telephony functionality
397 // (like making outgoing calls.)
Santos Cordon69a69192013-08-22 14:25:42 -0700398 callController = CallController.init(this, callLogger, callGatewayManager);
399
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700400 // Create the CallerInfoCache singleton, which remembers custom ring tone and
401 // send-to-voicemail settings.
402 //
403 // The asynchronous caching will start just after this call.
404 callerInfoCache = CallerInfoCache.init(this);
405
406 // Monitors call activity from the telephony layer
407 callStateMonitor = new CallStateMonitor(mCM);
408
Santos Cordon593ab382013-08-06 21:58:23 -0700409 // Manages wired headset state
410 wiredHeadsetManager = new WiredHeadsetManager(this);
Santos Cordon593ab382013-08-06 21:58:23 -0700411
Santos Cordon2c2d3cf2013-08-08 03:53:47 -0700412 // Bluetooth manager
Sailesh Nepal23d9ed72014-07-03 09:40:26 -0700413 bluetoothManager = new BluetoothManager();
Santos Cordon2c2d3cf2013-08-08 03:53:47 -0700414
415 ringer = Ringer.init(this, bluetoothManager);
416
Santos Cordon9b7bac72013-08-06 08:04:52 -0700417 // Audio router
Santos Cordon593ab382013-08-06 21:58:23 -0700418 audioRouter = new AudioRouter(this, bluetoothManager, wiredHeadsetManager, mCM);
Santos Cordon9b7bac72013-08-06 08:04:52 -0700419
Sailesh Nepal194161e2014-07-03 08:57:44 -0700420 phoneMgr = PhoneInterfaceManager.init(this, phone);
Santos Cordon406c0342013-08-28 00:07:47 -0700421
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700422 // Create the CallNotifer singleton, which handles
423 // asynchronous events from the telephony layer (like
424 // launching the incoming-call UI when an incoming call comes
425 // in.)
Santos Cordon27a3c1f2013-08-06 07:49:27 -0700426 notifier = CallNotifier.init(this, phone, ringer, callLogger, callStateMonitor,
Sailesh Nepal23d9ed72014-07-03 09:40:26 -0700427 bluetoothManager);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700428
429 // register for ICC status
430 IccCard sim = phone.getIccCard();
431 if (sim != null) {
432 if (VDBG) Log.v(LOG_TAG, "register for ICC status");
433 sim.registerForNetworkLocked(mHandler, EVENT_SIM_NETWORK_LOCKED, null);
434 }
435
436 // register for MMI/USSD
437 mCM.registerForMmiComplete(mHandler, MMI_COMPLETE, null);
438
439 // register connection tracking to PhoneUtils
440 PhoneUtils.initializeConnectionHandler(mCM);
441
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700442 // Register for misc other intent broadcasts.
443 IntentFilter intentFilter =
444 new IntentFilter(Intent.ACTION_AIRPLANE_MODE_CHANGED);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700445 intentFilter.addAction(TelephonyIntents.ACTION_ANY_DATA_CONNECTION_STATE_CHANGED);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700446 intentFilter.addAction(Intent.ACTION_DOCK_EVENT);
447 intentFilter.addAction(TelephonyIntents.ACTION_SIM_STATE_CHANGED);
448 intentFilter.addAction(TelephonyIntents.ACTION_RADIO_TECHNOLOGY_CHANGED);
449 intentFilter.addAction(TelephonyIntents.ACTION_SERVICE_STATE_CHANGED);
450 intentFilter.addAction(TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700451 intentFilter.addAction(AudioManager.RINGER_MODE_CHANGED_ACTION);
452 registerReceiver(mReceiver, intentFilter);
453
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700454 //set the default values for the preferences in the phone.
455 PreferenceManager.setDefaultValues(this, R.xml.network_setting, false);
456
457 PreferenceManager.setDefaultValues(this, R.xml.call_feature_setting, false);
458
459 // Make sure the audio mode (along with some
460 // audio-mode-related state of our own) is initialized
461 // correctly, given the current state of the phone.
462 PhoneUtils.setAudioMode(mCM);
463 }
464
465 if (TelephonyCapabilities.supportsOtasp(phone)) {
466 cdmaOtaProvisionData = new OtaUtils.CdmaOtaProvisionData();
467 cdmaOtaConfigData = new OtaUtils.CdmaOtaConfigData();
468 cdmaOtaScreenState = new OtaUtils.CdmaOtaScreenState();
469 cdmaOtaInCallScreenUiState = new OtaUtils.CdmaOtaInCallScreenUiState();
470 }
471
472 // XXX pre-load the SimProvider so that it's ready
473 resolver.getType(Uri.parse("content://icc/adn"));
474
475 // start with the default value to set the mute state.
476 mShouldRestoreMuteOnInCallResume = false;
477
478 // TODO: Register for Cdma Information Records
479 // phone.registerCdmaInformationRecord(mHandler, EVENT_UNSOL_CDMA_INFO_RECORD, null);
480
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700481 // Read HAC settings and configure audio hardware
482 if (getResources().getBoolean(R.bool.hac_enabled)) {
483 int hac = android.provider.Settings.System.getInt(phone.getContext().getContentResolver(),
484 android.provider.Settings.System.HEARING_AID,
485 0);
486 AudioManager audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
487 audioManager.setParameter(CallFeaturesSetting.HAC_KEY, hac != 0 ?
488 CallFeaturesSetting.HAC_VAL_ON :
489 CallFeaturesSetting.HAC_VAL_OFF);
490 }
Santos Cordonff506f52013-11-21 19:13:19 -0800491 }
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700492
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700493 /**
494 * Returns the singleton instance of the PhoneApp.
495 */
Sailesh Nepal1eaf22b2014-02-22 17:00:49 -0800496 public static PhoneGlobals getInstance() {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700497 if (sMe == null) {
498 throw new IllegalStateException("No PhoneGlobals here!");
499 }
500 return sMe;
501 }
502
503 /**
504 * Returns the singleton instance of the PhoneApp if running as the
505 * primary user, otherwise null.
506 */
507 static PhoneGlobals getInstanceIfPrimary() {
508 return sMe;
509 }
510
511 /**
512 * Returns the Phone associated with this instance
513 */
514 static Phone getPhone() {
515 return getInstance().phone;
516 }
517
518 Ringer getRinger() {
519 return ringer;
520 }
521
522 IBluetoothHeadsetPhone getBluetoothPhoneService() {
523 return mBluetoothPhone;
524 }
525
Santos Cordon27a3c1f2013-08-06 07:49:27 -0700526 /* package */ BluetoothManager getBluetoothManager() {
527 return bluetoothManager;
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700528 }
529
Santos Cordon593ab382013-08-06 21:58:23 -0700530 /* package */ WiredHeadsetManager getWiredHeadsetManager() {
531 return wiredHeadsetManager;
532 }
533
534 /* package */ AudioRouter getAudioRouter() {
535 return audioRouter;
536 }
537
Santos Cordonde10b752013-09-19 04:11:33 -0700538 /* package */ CallManager getCallManager() {
539 return mCM;
540 }
541
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700542 /**
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700543 * Returns PendingIntent for hanging up ongoing phone call. This will typically be used from
544 * Notification context.
545 */
546 /* package */ static PendingIntent createHangUpOngoingCallPendingIntent(Context context) {
547 Intent intent = new Intent(PhoneGlobals.ACTION_HANG_UP_ONGOING_CALL, null,
548 context, NotificationBroadcastReceiver.class);
549 return PendingIntent.getBroadcast(context, 0, intent, 0);
550 }
551
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700552 boolean isSimPinEnabled() {
553 return mIsSimPinEnabled;
554 }
555
556 boolean authenticateAgainstCachedSimPin(String pin) {
557 return (mCachedSimPin != null && mCachedSimPin.equals(pin));
558 }
559
560 void setCachedSimPin(String pin) {
561 mCachedSimPin = pin;
562 }
563
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700564 /**
565 * Handles OTASP-related events from the telephony layer.
566 *
567 * While an OTASP call is active, the CallNotifier forwards
568 * OTASP-related telephony events to this method.
569 */
570 void handleOtaspEvent(Message msg) {
571 if (DBG) Log.d(LOG_TAG, "handleOtaspEvent(message " + msg + ")...");
572
573 if (otaUtils == null) {
574 // We shouldn't be getting OTASP events without ever
575 // having started the OTASP call in the first place!
576 Log.w(LOG_TAG, "handleOtaEvents: got an event but otaUtils is null! "
577 + "message = " + msg);
578 return;
579 }
580
581 otaUtils.onOtaProvisionStatusChanged((AsyncResult) msg.obj);
582 }
583
584 /**
585 * Similarly, handle the disconnect event of an OTASP call
586 * by forwarding it to the OtaUtils instance.
587 */
588 /* package */ void handleOtaspDisconnect() {
589 if (DBG) Log.d(LOG_TAG, "handleOtaspDisconnect()...");
590
591 if (otaUtils == null) {
592 // We shouldn't be getting OTASP events without ever
593 // having started the OTASP call in the first place!
594 Log.w(LOG_TAG, "handleOtaspDisconnect: otaUtils is null!");
595 return;
596 }
597
598 otaUtils.onOtaspDisconnect();
599 }
600
601 /**
602 * Sets the activity responsible for un-PUK-blocking the device
603 * so that we may close it when we receive a positive result.
604 * mPUKEntryActivity is also used to indicate to the device that
605 * we are trying to un-PUK-lock the phone. In other words, iff
606 * it is NOT null, then we are trying to unlock and waiting for
607 * the SIM to move to READY state.
608 *
609 * @param activity is the activity to close when PUK has
610 * finished unlocking. Can be set to null to indicate the unlock
611 * or SIM READYing process is over.
612 */
613 void setPukEntryActivity(Activity activity) {
614 mPUKEntryActivity = activity;
615 }
616
617 Activity getPUKEntryActivity() {
618 return mPUKEntryActivity;
619 }
620
621 /**
622 * Sets the dialog responsible for notifying the user of un-PUK-
623 * blocking - SIM READYing progress, so that we may dismiss it
624 * when we receive a positive result.
625 *
626 * @param dialog indicates the progress dialog informing the user
627 * of the state of the device. Dismissed upon completion of
628 * READYing process
629 */
630 void setPukEntryProgressDialog(ProgressDialog dialog) {
631 mPUKEntryProgressDialog = dialog;
632 }
633
634 ProgressDialog getPUKEntryProgressDialog() {
635 return mPUKEntryProgressDialog;
636 }
637
638 /**
639 * Controls whether or not the screen is allowed to sleep.
640 *
641 * Once sleep is allowed (WakeState is SLEEP), it will rely on the
642 * settings for the poke lock to determine when to timeout and let
643 * the device sleep {@link PhoneGlobals#setScreenTimeout}.
644 *
645 * @param ws tells the device to how to wake.
646 */
647 /* package */ void requestWakeState(WakeState ws) {
648 if (VDBG) Log.d(LOG_TAG, "requestWakeState(" + ws + ")...");
649 synchronized (this) {
650 if (mWakeState != ws) {
651 switch (ws) {
652 case PARTIAL:
653 // acquire the processor wake lock, and release the FULL
654 // lock if it is being held.
655 mPartialWakeLock.acquire();
656 if (mWakeLock.isHeld()) {
657 mWakeLock.release();
658 }
659 break;
660 case FULL:
661 // acquire the full wake lock, and release the PARTIAL
662 // lock if it is being held.
663 mWakeLock.acquire();
664 if (mPartialWakeLock.isHeld()) {
665 mPartialWakeLock.release();
666 }
667 break;
668 case SLEEP:
669 default:
670 // release both the PARTIAL and FULL locks.
671 if (mWakeLock.isHeld()) {
672 mWakeLock.release();
673 }
674 if (mPartialWakeLock.isHeld()) {
675 mPartialWakeLock.release();
676 }
677 break;
678 }
679 mWakeState = ws;
680 }
681 }
682 }
683
684 /**
685 * If we are not currently keeping the screen on, then poke the power
686 * manager to wake up the screen for the user activity timeout duration.
687 */
688 /* package */ void wakeUpScreen() {
689 synchronized (this) {
690 if (mWakeState == WakeState.SLEEP) {
691 if (DBG) Log.d(LOG_TAG, "pulse screen lock");
692 mPowerManager.wakeUp(SystemClock.uptimeMillis());
693 }
694 }
695 }
696
697 /**
698 * Sets the wake state and screen timeout based on the current state
699 * of the phone, and the current state of the in-call UI.
700 *
701 * This method is a "UI Policy" wrapper around
702 * {@link PhoneGlobals#requestWakeState} and {@link PhoneGlobals#setScreenTimeout}.
703 *
704 * It's safe to call this method regardless of the state of the Phone
705 * (e.g. whether or not it's idle), and regardless of the state of the
706 * Phone UI (e.g. whether or not the InCallScreen is active.)
707 */
708 /* package */ void updateWakeState() {
709 PhoneConstants.State state = mCM.getState();
710
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700711 // True if the speakerphone is in use. (If so, we *always* use
712 // the default timeout. Since the user is obviously not holding
713 // the phone up to his/her face, we don't need to worry about
714 // false touches, and thus don't need to turn the screen off so
715 // aggressively.)
716 // Note that we need to make a fresh call to this method any
717 // time the speaker state changes. (That happens in
718 // PhoneUtils.turnOnSpeaker().)
719 boolean isSpeakerInUse = (state == PhoneConstants.State.OFFHOOK) && PhoneUtils.isSpeakerOn(this);
720
721 // TODO (bug 1440854): The screen timeout *might* also need to
722 // depend on the bluetooth state, but this isn't as clear-cut as
723 // the speaker state (since while using BT it's common for the
724 // user to put the phone straight into a pocket, in which case the
725 // timeout should probably still be short.)
726
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700727 // Decide whether to force the screen on or not.
728 //
729 // Force the screen to be on if the phone is ringing or dialing,
730 // or if we're displaying the "Call ended" UI for a connection in
731 // the "disconnected" state.
732 // However, if the phone is disconnected while the user is in the
733 // middle of selecting a quick response message, we should not force
734 // the screen to be on.
735 //
736 boolean isRinging = (state == PhoneConstants.State.RINGING);
737 boolean isDialing = (phone.getForegroundCall().getState() == Call.State.DIALING);
Jay Shrauner6fe8fd62013-09-16 19:39:30 -0700738 boolean keepScreenOn = isRinging || isDialing;
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700739 // keepScreenOn == true means we'll hold a full wake lock:
740 requestWakeState(keepScreenOn ? WakeState.FULL : WakeState.SLEEP);
741 }
742
743 /**
744 * Manually pokes the PowerManager's userActivity method. Since we
745 * set the {@link WindowManager.LayoutParams#INPUT_FEATURE_DISABLE_USER_ACTIVITY}
746 * flag while the InCallScreen is active when there is no proximity sensor,
747 * we need to do this for touch events that really do count as user activity
748 * (like pressing any onscreen UI elements.)
749 */
750 /* package */ void pokeUserActivity() {
751 if (VDBG) Log.d(LOG_TAG, "pokeUserActivity()...");
752 mPowerManager.userActivity(SystemClock.uptimeMillis(), false);
753 }
754
755 /**
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700756 * Notifies the phone app when the phone state changes.
757 *
Santos Cordonfc309812013-08-20 18:33:16 -0700758 * This method will updates various states inside Phone app (e.g. update-lock state, etc.)
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700759 */
760 /* package */ void updatePhoneState(PhoneConstants.State state) {
761 if (state != mLastPhoneState) {
762 mLastPhoneState = state;
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700763
764 // Try to acquire or release UpdateLock.
765 //
766 // Watch out: we don't release the lock here when the screen is still in foreground.
767 // At that time InCallScreen will release it on onPause().
768 if (state != PhoneConstants.State.IDLE) {
769 // UpdateLock is a recursive lock, while we may get "acquire" request twice and
770 // "release" request once for a single call (RINGING + OFFHOOK and IDLE).
771 // We need to manually ensure the lock is just acquired once for each (and this
772 // will prevent other possible buggy situations too).
773 if (!mUpdateLock.isHeld()) {
774 mUpdateLock.acquire();
775 }
776 } else {
Jay Shraunera5d13212013-09-19 13:37:43 -0700777 if (mUpdateLock.isHeld()) {
Jay Shrauner6fe8fd62013-09-16 19:39:30 -0700778 mUpdateLock.release();
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700779 }
780 }
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700781 }
782 }
783
784 /* package */ PhoneConstants.State getPhoneState() {
785 return mLastPhoneState;
786 }
787
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700788 KeyguardManager getKeyguardManager() {
789 return mKeyguardManager;
790 }
791
792 private void onMMIComplete(AsyncResult r) {
793 if (VDBG) Log.d(LOG_TAG, "onMMIComplete()...");
794 MmiCode mmiCode = (MmiCode) r.result;
795 PhoneUtils.displayMMIComplete(phone, getInstance(), mmiCode, null, null);
796 }
797
798 private void initForNewRadioTechnology() {
799 if (DBG) Log.d(LOG_TAG, "initForNewRadioTechnology...");
800
801 if (phone.getPhoneType() == PhoneConstants.PHONE_TYPE_CDMA) {
802 // Create an instance of CdmaPhoneCallState and initialize it to IDLE
803 cdmaPhoneCallState = new CdmaPhoneCallState();
804 cdmaPhoneCallState.CdmaPhoneCallStateInit();
805 }
806 if (TelephonyCapabilities.supportsOtasp(phone)) {
807 //create instances of CDMA OTA data classes
808 if (cdmaOtaProvisionData == null) {
809 cdmaOtaProvisionData = new OtaUtils.CdmaOtaProvisionData();
810 }
811 if (cdmaOtaConfigData == null) {
812 cdmaOtaConfigData = new OtaUtils.CdmaOtaConfigData();
813 }
814 if (cdmaOtaScreenState == null) {
815 cdmaOtaScreenState = new OtaUtils.CdmaOtaScreenState();
816 }
817 if (cdmaOtaInCallScreenUiState == null) {
818 cdmaOtaInCallScreenUiState = new OtaUtils.CdmaOtaInCallScreenUiState();
819 }
820 } else {
821 //Clean up OTA data in GSM/UMTS. It is valid only for CDMA
822 clearOtaState();
823 }
824
825 ringer.updateRingerContextAfterRadioTechnologyChange(this.phone);
826 notifier.updateCallNotifierRegistrationsAfterRadioTechnologyChange();
827 callStateMonitor.updateAfterRadioTechnologyChange();
828
829 if (mBluetoothPhone != null) {
830 try {
831 mBluetoothPhone.updateBtHandsfreeAfterRadioTechnologyChange();
832 } catch (RemoteException e) {
833 Log.e(LOG_TAG, Log.getStackTraceString(new Throwable()));
834 }
835 }
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700836
837 // Update registration for ICC status after radio technology change
838 IccCard sim = phone.getIccCard();
839 if (sim != null) {
840 if (DBG) Log.d(LOG_TAG, "Update registration for ICC status...");
841
842 //Register all events new to the new active phone
843 sim.registerForNetworkLocked(mHandler, EVENT_SIM_NETWORK_LOCKED, null);
844 }
845 }
846
Santos Cordon593ab382013-08-06 21:58:23 -0700847 /**
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700848 * Receiver for misc intent broadcasts the Phone app cares about.
849 */
850 private class PhoneAppBroadcastReceiver extends BroadcastReceiver {
851 @Override
852 public void onReceive(Context context, Intent intent) {
853 String action = intent.getAction();
854 if (action.equals(Intent.ACTION_AIRPLANE_MODE_CHANGED)) {
855 boolean enabled = System.getInt(getContentResolver(),
856 System.AIRPLANE_MODE_ON, 0) == 0;
857 phone.setRadioPower(enabled);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700858 } else if (action.equals(TelephonyIntents.ACTION_ANY_DATA_CONNECTION_STATE_CHANGED)) {
859 if (VDBG) Log.d(LOG_TAG, "mReceiver: ACTION_ANY_DATA_CONNECTION_STATE_CHANGED");
860 if (VDBG) Log.d(LOG_TAG, "- state: " + intent.getStringExtra(PhoneConstants.STATE_KEY));
861 if (VDBG) Log.d(LOG_TAG, "- reason: "
862 + intent.getStringExtra(PhoneConstants.STATE_CHANGE_REASON_KEY));
863
864 // The "data disconnected due to roaming" notification is shown
865 // if (a) you have the "data roaming" feature turned off, and
866 // (b) you just lost data connectivity because you're roaming.
867 boolean disconnectedDueToRoaming =
868 !phone.getDataRoamingEnabled()
869 && "DISCONNECTED".equals(intent.getStringExtra(PhoneConstants.STATE_KEY))
870 && Phone.REASON_ROAMING_ON.equals(
871 intent.getStringExtra(PhoneConstants.STATE_CHANGE_REASON_KEY));
872 mHandler.sendEmptyMessage(disconnectedDueToRoaming
873 ? EVENT_DATA_ROAMING_DISCONNECTED
874 : EVENT_DATA_ROAMING_OK);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700875 } else if ((action.equals(TelephonyIntents.ACTION_SIM_STATE_CHANGED)) &&
876 (mPUKEntryActivity != null)) {
877 // if an attempt to un-PUK-lock the device was made, while we're
878 // receiving this state change notification, notify the handler.
879 // NOTE: This is ONLY triggered if an attempt to un-PUK-lock has
880 // been attempted.
881 mHandler.sendMessage(mHandler.obtainMessage(EVENT_SIM_STATE_CHANGED,
882 intent.getStringExtra(IccCardConstants.INTENT_KEY_ICC_STATE)));
883 } else if (action.equals(TelephonyIntents.ACTION_RADIO_TECHNOLOGY_CHANGED)) {
884 String newPhone = intent.getStringExtra(PhoneConstants.PHONE_NAME_KEY);
885 Log.d(LOG_TAG, "Radio technology switched. Now " + newPhone + " is active.");
886 initForNewRadioTechnology();
887 } else if (action.equals(TelephonyIntents.ACTION_SERVICE_STATE_CHANGED)) {
888 handleServiceStateChanged(intent);
889 } else if (action.equals(TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED)) {
890 if (TelephonyCapabilities.supportsEcm(phone)) {
891 Log.d(LOG_TAG, "Emergency Callback Mode arrived in PhoneApp.");
892 // Start Emergency Callback Mode service
893 if (intent.getBooleanExtra("phoneinECMState", false)) {
894 context.startService(new Intent(context,
895 EmergencyCallbackModeService.class));
896 }
897 } else {
898 // It doesn't make sense to get ACTION_EMERGENCY_CALLBACK_MODE_CHANGED
899 // on a device that doesn't support ECM in the first place.
900 Log.e(LOG_TAG, "Got ACTION_EMERGENCY_CALLBACK_MODE_CHANGED, "
901 + "but ECM isn't supported for phone: " + phone.getPhoneName());
902 }
903 } else if (action.equals(Intent.ACTION_DOCK_EVENT)) {
904 mDockState = intent.getIntExtra(Intent.EXTRA_DOCK_STATE,
905 Intent.EXTRA_DOCK_STATE_UNDOCKED);
906 if (VDBG) Log.d(LOG_TAG, "ACTION_DOCK_EVENT -> mDockState = " + mDockState);
907 mHandler.sendMessage(mHandler.obtainMessage(EVENT_DOCK_STATE_CHANGED, 0));
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700908 } else if (action.equals(AudioManager.RINGER_MODE_CHANGED_ACTION)) {
909 int ringerMode = intent.getIntExtra(AudioManager.EXTRA_RINGER_MODE,
910 AudioManager.RINGER_MODE_NORMAL);
911 if (ringerMode == AudioManager.RINGER_MODE_SILENT) {
912 notifier.silenceRinger();
913 }
914 }
915 }
916 }
917
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700918 /**
919 * Accepts broadcast Intents which will be prepared by {@link NotificationMgr} and thus
920 * sent from framework's notification mechanism (which is outside Phone context).
921 * This should be visible from outside, but shouldn't be in "exported" state.
922 *
923 * TODO: If possible merge this into PhoneAppBroadcastReceiver.
924 */
925 public static class NotificationBroadcastReceiver extends BroadcastReceiver {
926 @Override
927 public void onReceive(Context context, Intent intent) {
928 String action = intent.getAction();
929 // TODO: use "if (VDBG)" here.
930 Log.d(LOG_TAG, "Broadcast from Notification: " + action);
931
932 if (action.equals(ACTION_HANG_UP_ONGOING_CALL)) {
933 PhoneUtils.hangup(PhoneGlobals.getInstance().mCM);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700934 } else {
935 Log.w(LOG_TAG, "Received hang-up request from notification,"
936 + " but there's no call the system can hang up.");
937 }
938 }
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700939 }
940
941 private void handleServiceStateChanged(Intent intent) {
942 /**
943 * This used to handle updating EriTextWidgetProvider this routine
944 * and and listening for ACTION_SERVICE_STATE_CHANGED intents could
945 * be removed. But leaving just in case it might be needed in the near
946 * future.
947 */
948
949 // If service just returned, start sending out the queued messages
950 ServiceState ss = ServiceState.newFromBundle(intent.getExtras());
951
952 if (ss != null) {
953 int state = ss.getState();
954 notificationMgr.updateNetworkSelection(state);
955 }
956 }
957
958 public boolean isOtaCallInActiveState() {
959 boolean otaCallActive = false;
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700960 if (VDBG) Log.d(LOG_TAG, "- isOtaCallInActiveState " + otaCallActive);
961 return otaCallActive;
962 }
963
964 public boolean isOtaCallInEndState() {
965 boolean otaCallEnded = false;
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700966 if (VDBG) Log.d(LOG_TAG, "- isOtaCallInEndState " + otaCallEnded);
967 return otaCallEnded;
968 }
969
970 // it is safe to call clearOtaState() even if the InCallScreen isn't active
971 public void clearOtaState() {
972 if (DBG) Log.d(LOG_TAG, "- clearOtaState ...");
Jay Shrauner6fe8fd62013-09-16 19:39:30 -0700973 if (otaUtils != null) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700974 otaUtils.cleanOtaScreen(true);
975 if (DBG) Log.d(LOG_TAG, " - clearOtaState clears OTA screen");
976 }
977 }
978
979 // it is safe to call dismissOtaDialogs() even if the InCallScreen isn't active
980 public void dismissOtaDialogs() {
981 if (DBG) Log.d(LOG_TAG, "- dismissOtaDialogs ...");
Jay Shrauner6fe8fd62013-09-16 19:39:30 -0700982 if (otaUtils != null) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700983 otaUtils.dismissAllOtaDialogs();
984 if (DBG) Log.d(LOG_TAG, " - dismissOtaDialogs clears OTA dialogs");
985 }
986 }
987
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700988 /**
989 * "Call origin" may be used by Contacts app to specify where the phone call comes from.
990 * Currently, the only permitted value for this extra is {@link #ALLOWED_EXTRA_CALL_ORIGIN}.
991 * Any other value will be ignored, to make sure that malicious apps can't trick the in-call
992 * UI into launching some random other app after a call ends.
993 *
994 * TODO: make this more generic. Note that we should let the "origin" specify its package
995 * while we are now assuming it is "com.android.contacts"
996 */
997 public static final String EXTRA_CALL_ORIGIN = "com.android.phone.CALL_ORIGIN";
998 private static final String DEFAULT_CALL_ORIGIN_PACKAGE = "com.android.dialer";
999 private static final String ALLOWED_EXTRA_CALL_ORIGIN =
1000 "com.android.dialer.DialtactsActivity";
1001 /**
1002 * Used to determine if the preserved call origin is fresh enough.
1003 */
1004 private static final long CALL_ORIGIN_EXPIRATION_MILLIS = 30 * 1000;
1005
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001006 /** Service connection */
1007 private final ServiceConnection mBluetoothPhoneConnection = new ServiceConnection() {
1008
1009 /** Handle the task of binding the local object to the service */
1010 public void onServiceConnected(ComponentName className, IBinder service) {
1011 Log.i(LOG_TAG, "Headset phone created, binding local service.");
1012 mBluetoothPhone = IBluetoothHeadsetPhone.Stub.asInterface(service);
1013 }
1014
1015 /** Handle the task of cleaning up the local binding */
1016 public void onServiceDisconnected(ComponentName className) {
1017 Log.i(LOG_TAG, "Headset phone disconnected, cleaning local binding.");
1018 mBluetoothPhone = null;
1019 }
1020 };
Santos Cordon83570472013-09-06 15:45:10 -07001021
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001022}