• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
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 
17 package com.android.phone;
18 
19 import android.app.Activity;
20 import android.app.Application;
21 import android.app.KeyguardManager;
22 import android.app.ProgressDialog;
23 import android.bluetooth.BluetoothAdapter;
24 import android.bluetooth.BluetoothHeadset;
25 import android.bluetooth.BluetoothProfile;
26 import android.content.ActivityNotFoundException;
27 import android.content.BroadcastReceiver;
28 import android.content.ContentResolver;
29 import android.content.Context;
30 import android.content.Intent;
31 import android.content.IntentFilter;
32 import android.content.res.Configuration;
33 import android.media.AudioManager;
34 import android.net.Uri;
35 import android.os.AsyncResult;
36 import android.os.Binder;
37 import android.os.Handler;
38 import android.os.IBinder;
39 import android.os.IPowerManager;
40 import android.os.LocalPowerManager;
41 import android.os.Message;
42 import android.os.PowerManager;
43 import android.os.RemoteException;
44 import android.os.ServiceManager;
45 import android.os.SystemClock;
46 import android.os.SystemProperties;
47 import android.preference.PreferenceManager;
48 import android.provider.Settings.System;
49 import android.telephony.ServiceState;
50 import android.text.TextUtils;
51 import android.util.Log;
52 import android.view.KeyEvent;
53 
54 import com.android.internal.telephony.Call;
55 import com.android.internal.telephony.CallManager;
56 import com.android.internal.telephony.IccCard;
57 import com.android.internal.telephony.MmiCode;
58 import com.android.internal.telephony.Phone;
59 import com.android.internal.telephony.PhoneFactory;
60 import com.android.internal.telephony.TelephonyIntents;
61 import com.android.internal.telephony.cdma.TtyIntent;
62 import com.android.phone.OtaUtils.CdmaOtaScreenState;
63 import com.android.server.sip.SipService;
64 
65 /**
66  * Top-level Application class for the Phone app.
67  */
68 public class PhoneApp extends Application implements AccelerometerListener.OrientationListener {
69     /* package */ static final String LOG_TAG = "PhoneApp";
70 
71     /**
72      * Phone app-wide debug level:
73      *   0 - no debug logging
74      *   1 - normal debug logging if ro.debuggable is set (which is true in
75      *       "eng" and "userdebug" builds but not "user" builds)
76      *   2 - ultra-verbose debug logging
77      *
78      * Most individual classes in the phone app have a local DBG constant,
79      * typically set to
80      *   (PhoneApp.DBG_LEVEL >= 1) && (SystemProperties.getInt("ro.debuggable", 0) == 1)
81      * or else
82      *   (PhoneApp.DBG_LEVEL >= 2)
83      * depending on the desired verbosity.
84      *
85      * ***** DO NOT SUBMIT WITH DBG_LEVEL > 0 *************
86      */
87     /* package */ static final int DBG_LEVEL = 0;
88 
89     private static final boolean DBG =
90             (PhoneApp.DBG_LEVEL >= 1) && (SystemProperties.getInt("ro.debuggable", 0) == 1);
91     private static final boolean VDBG = (PhoneApp.DBG_LEVEL >= 2);
92 
93     // Message codes; see mHandler below.
94     private static final int EVENT_SIM_NETWORK_LOCKED = 3;
95     private static final int EVENT_WIRED_HEADSET_PLUG = 7;
96     private static final int EVENT_SIM_STATE_CHANGED = 8;
97     private static final int EVENT_UPDATE_INCALL_NOTIFICATION = 9;
98     private static final int EVENT_DATA_ROAMING_DISCONNECTED = 10;
99     private static final int EVENT_DATA_ROAMING_OK = 11;
100     private static final int EVENT_UNSOL_CDMA_INFO_RECORD = 12;
101     private static final int EVENT_DOCK_STATE_CHANGED = 13;
102     private static final int EVENT_TTY_PREFERRED_MODE_CHANGED = 14;
103     private static final int EVENT_TTY_MODE_GET = 15;
104     private static final int EVENT_TTY_MODE_SET = 16;
105     private static final int EVENT_START_SIP_SERVICE = 17;
106 
107     // The MMI codes are also used by the InCallScreen.
108     public static final int MMI_INITIATE = 51;
109     public static final int MMI_COMPLETE = 52;
110     public static final int MMI_CANCEL = 53;
111     // Don't use message codes larger than 99 here; those are reserved for
112     // the individual Activities of the Phone UI.
113 
114     /**
115      * Allowable values for the poke lock code (timeout between a user activity and the
116      * going to sleep), please refer to {@link com.android.server.PowerManagerService}
117      * for additional reference.
118      *   SHORT uses the short delay for the timeout (SHORT_KEYLIGHT_DELAY, 6 sec)
119      *   MEDIUM uses the medium delay for the timeout (MEDIUM_KEYLIGHT_DELAY, 15 sec)
120      *   DEFAULT is the system-wide default delay for the timeout (1 min)
121      */
122     public enum ScreenTimeoutDuration {
123         SHORT,
124         MEDIUM,
125         DEFAULT
126     }
127 
128     /**
129      * Allowable values for the wake lock code.
130      *   SLEEP means the device can be put to sleep.
131      *   PARTIAL means wake the processor, but we display can be kept off.
132      *   FULL means wake both the processor and the display.
133      */
134     public enum WakeState {
135         SLEEP,
136         PARTIAL,
137         FULL
138     }
139 
140     private static PhoneApp sMe;
141 
142     // A few important fields we expose to the rest of the package
143     // directly (rather than thru set/get methods) for efficiency.
144     Phone phone;
145     CallController callController;
146     InCallUiState inCallUiState;
147     CallNotifier notifier;
148     NotificationMgr notificationMgr;
149     Ringer ringer;
150     BluetoothHandsfree mBtHandsfree;
151     PhoneInterfaceManager phoneMgr;
152     CallManager mCM;
153     int mBluetoothHeadsetState = BluetoothProfile.STATE_DISCONNECTED;
154     int mBluetoothHeadsetAudioState = BluetoothHeadset.STATE_AUDIO_DISCONNECTED;
155     boolean mShowBluetoothIndication = false;
156     static int mDockState = Intent.EXTRA_DOCK_STATE_UNDOCKED;
157     static boolean sVoiceCapable = true;
158 
159     // Internal PhoneApp Call state tracker
160     CdmaPhoneCallState cdmaPhoneCallState;
161 
162     // The InCallScreen instance (or null if the InCallScreen hasn't been
163     // created yet.)
164     private InCallScreen mInCallScreen;
165 
166     // The currently-active PUK entry activity and progress dialog.
167     // Normally, these are the Emergency Dialer and the subsequent
168     // progress dialog.  null if there is are no such objects in
169     // the foreground.
170     private Activity mPUKEntryActivity;
171     private ProgressDialog mPUKEntryProgressDialog;
172 
173     private boolean mIsSimPinEnabled;
174     private String mCachedSimPin;
175 
176     // True if a wired headset is currently plugged in, based on the state
177     // from the latest Intent.ACTION_HEADSET_PLUG broadcast we received in
178     // mReceiver.onReceive().
179     private boolean mIsHeadsetPlugged;
180 
181     // True if the keyboard is currently *not* hidden
182     // Gets updated whenever there is a Configuration change
183     private boolean mIsHardKeyboardOpen;
184 
185     // True if we are beginning a call, but the phone state has not changed yet
186     private boolean mBeginningCall;
187 
188     // Last phone state seen by updatePhoneState()
189     Phone.State mLastPhoneState = Phone.State.IDLE;
190 
191     private WakeState mWakeState = WakeState.SLEEP;
192     private ScreenTimeoutDuration mScreenTimeoutDuration = ScreenTimeoutDuration.DEFAULT;
193     private boolean mIgnoreTouchUserActivity = false;
194     private IBinder mPokeLockToken = new Binder();
195     private IPowerManager mPowerManagerService;
196     private PowerManager.WakeLock mWakeLock;
197     private PowerManager.WakeLock mPartialWakeLock;
198     private PowerManager.WakeLock mProximityWakeLock;
199     private KeyguardManager mKeyguardManager;
200     private AccelerometerListener mAccelerometerListener;
201     private int mOrientation = AccelerometerListener.ORIENTATION_UNKNOWN;
202 
203     // Broadcast receiver for various intent broadcasts (see onCreate())
204     private final BroadcastReceiver mReceiver = new PhoneAppBroadcastReceiver();
205 
206     // Broadcast receiver purely for ACTION_MEDIA_BUTTON broadcasts
207     private final BroadcastReceiver mMediaButtonReceiver = new MediaButtonBroadcastReceiver();
208 
209     /** boolean indicating restoring mute state on InCallScreen.onResume() */
210     private boolean mShouldRestoreMuteOnInCallResume;
211 
212     /**
213      * The singleton OtaUtils instance used for OTASP calls.
214      *
215      * The OtaUtils instance is created lazily the first time we need to
216      * make an OTASP call, regardless of whether it's an interactive or
217      * non-interactive OTASP call.
218      */
219     public OtaUtils otaUtils;
220 
221     // Following are the CDMA OTA information Objects used during OTA Call.
222     // cdmaOtaProvisionData object store static OTA information that needs
223     // to be maintained even during Slider open/close scenarios.
224     // cdmaOtaConfigData object stores configuration info to control visiblity
225     // of each OTA Screens.
226     // cdmaOtaScreenState object store OTA Screen State information.
227     public OtaUtils.CdmaOtaProvisionData cdmaOtaProvisionData;
228     public OtaUtils.CdmaOtaConfigData cdmaOtaConfigData;
229     public OtaUtils.CdmaOtaScreenState cdmaOtaScreenState;
230     public OtaUtils.CdmaOtaInCallScreenUiState cdmaOtaInCallScreenUiState;
231 
232     // TTY feature enabled on this platform
233     private boolean mTtyEnabled;
234     // Current TTY operating mode selected by user
235     private int mPreferredTtyMode = Phone.TTY_MODE_OFF;
236 
237     /**
238      * Set the restore mute state flag. Used when we are setting the mute state
239      * OUTSIDE of user interaction {@link PhoneUtils#startNewCall(Phone)}
240      */
setRestoreMuteOnInCallResume(boolean mode)241     /*package*/void setRestoreMuteOnInCallResume (boolean mode) {
242         mShouldRestoreMuteOnInCallResume = mode;
243     }
244 
245     /**
246      * Get the restore mute state flag.
247      * This is used by the InCallScreen {@link InCallScreen#onResume()} to figure
248      * out if we need to restore the mute state for the current active call.
249      */
getRestoreMuteOnInCallResume()250     /*package*/boolean getRestoreMuteOnInCallResume () {
251         return mShouldRestoreMuteOnInCallResume;
252     }
253 
254     Handler mHandler = new Handler() {
255         @Override
256         public void handleMessage(Message msg) {
257             Phone.State phoneState;
258             switch (msg.what) {
259                 // Starts the SIP service. It's a no-op if SIP API is not supported
260                 // on the deivce.
261                 // TODO: Having the phone process host the SIP service is only
262                 // temporary. Will move it to a persistent communication process
263                 // later.
264                 case EVENT_START_SIP_SERVICE:
265                     SipService.start(getApplicationContext());
266                     break;
267 
268                 // TODO: This event should be handled by the lock screen, just
269                 // like the "SIM missing" and "Sim locked" cases (bug 1804111).
270                 case EVENT_SIM_NETWORK_LOCKED:
271                     if (getResources().getBoolean(R.bool.ignore_sim_network_locked_events)) {
272                         // Some products don't have the concept of a "SIM network lock"
273                         Log.i(LOG_TAG, "Ignoring EVENT_SIM_NETWORK_LOCKED event; "
274                               + "not showing 'SIM network unlock' PIN entry screen");
275                     } else {
276                         // Normal case: show the "SIM network unlock" PIN entry screen.
277                         // The user won't be able to do anything else until
278                         // they enter a valid SIM network PIN.
279                         Log.i(LOG_TAG, "show sim depersonal panel");
280                         IccNetworkDepersonalizationPanel ndpPanel =
281                                 new IccNetworkDepersonalizationPanel(PhoneApp.getInstance());
282                         ndpPanel.show();
283                     }
284                     break;
285 
286                 case EVENT_UPDATE_INCALL_NOTIFICATION:
287                     // Tell the NotificationMgr to update the "ongoing
288                     // call" icon in the status bar, if necessary.
289                     // Currently, this is triggered by a bluetooth headset
290                     // state change (since the status bar icon needs to
291                     // turn blue when bluetooth is active.)
292                     if (DBG) Log.d (LOG_TAG, "- updating in-call notification from handler...");
293                     notificationMgr.updateInCallNotification();
294                     break;
295 
296                 case EVENT_DATA_ROAMING_DISCONNECTED:
297                     notificationMgr.showDataDisconnectedRoaming();
298                     break;
299 
300                 case EVENT_DATA_ROAMING_OK:
301                     notificationMgr.hideDataDisconnectedRoaming();
302                     break;
303 
304                 case MMI_COMPLETE:
305                     onMMIComplete((AsyncResult) msg.obj);
306                     break;
307 
308                 case MMI_CANCEL:
309                     PhoneUtils.cancelMmiCode(phone);
310                     break;
311 
312                 case EVENT_WIRED_HEADSET_PLUG:
313                     // Since the presence of a wired headset or bluetooth affects the
314                     // speakerphone, update the "speaker" state.  We ONLY want to do
315                     // this on the wired headset connect / disconnect events for now
316                     // though, so we're only triggering on EVENT_WIRED_HEADSET_PLUG.
317 
318                     phoneState = mCM.getState();
319                     // Do not change speaker state if phone is not off hook
320                     if (phoneState == Phone.State.OFFHOOK) {
321                         if (mBtHandsfree == null || !mBtHandsfree.isAudioOn()) {
322                             if (!isHeadsetPlugged()) {
323                                 // if the state is "not connected", restore the speaker state.
324                                 PhoneUtils.restoreSpeakerMode(getApplicationContext());
325                             } else {
326                                 // if the state is "connected", force the speaker off without
327                                 // storing the state.
328                                 PhoneUtils.turnOnSpeaker(getApplicationContext(), false, false);
329                             }
330                         }
331                     }
332                     // Update the Proximity sensor based on headset state
333                     updateProximitySensorMode(phoneState);
334 
335                     // Force TTY state update according to new headset state
336                     if (mTtyEnabled) {
337                         sendMessage(obtainMessage(EVENT_TTY_PREFERRED_MODE_CHANGED, 0));
338                     }
339                     break;
340 
341                 case EVENT_SIM_STATE_CHANGED:
342                     // Marks the event where the SIM goes into ready state.
343                     // Right now, this is only used for the PUK-unlocking
344                     // process.
345                     if (msg.obj.equals(IccCard.INTENT_VALUE_ICC_READY)) {
346                         // when the right event is triggered and there
347                         // are UI objects in the foreground, we close
348                         // them to display the lock panel.
349                         if (mPUKEntryActivity != null) {
350                             mPUKEntryActivity.finish();
351                             mPUKEntryActivity = null;
352                         }
353                         if (mPUKEntryProgressDialog != null) {
354                             mPUKEntryProgressDialog.dismiss();
355                             mPUKEntryProgressDialog = null;
356                         }
357                     }
358                     break;
359 
360                 case EVENT_UNSOL_CDMA_INFO_RECORD:
361                     //TODO: handle message here;
362                     break;
363 
364                 case EVENT_DOCK_STATE_CHANGED:
365                     // If the phone is docked/undocked during a call, and no wired or BT headset
366                     // is connected: turn on/off the speaker accordingly.
367                     boolean inDockMode = false;
368                     if (mDockState == Intent.EXTRA_DOCK_STATE_DESK ||
369                             mDockState == Intent.EXTRA_DOCK_STATE_CAR) {
370                         inDockMode = true;
371                     }
372                     if (VDBG) Log.d(LOG_TAG, "received EVENT_DOCK_STATE_CHANGED. Phone inDock = "
373                             + inDockMode);
374 
375                     phoneState = mCM.getState();
376                     if (phoneState == Phone.State.OFFHOOK &&
377                             !isHeadsetPlugged() &&
378                             !(mBtHandsfree != null && mBtHandsfree.isAudioOn())) {
379                         PhoneUtils.turnOnSpeaker(getApplicationContext(), inDockMode, true);
380                         updateInCallScreen();  // Has no effect if the InCallScreen isn't visible
381                     }
382                     break;
383 
384                 case EVENT_TTY_PREFERRED_MODE_CHANGED:
385                     // TTY mode is only applied if a headset is connected
386                     int ttyMode;
387                     if (isHeadsetPlugged()) {
388                         ttyMode = mPreferredTtyMode;
389                     } else {
390                         ttyMode = Phone.TTY_MODE_OFF;
391                     }
392                     phone.setTTYMode(ttyMode, mHandler.obtainMessage(EVENT_TTY_MODE_SET));
393                     break;
394 
395                 case EVENT_TTY_MODE_GET:
396                     handleQueryTTYModeResponse(msg);
397                     break;
398 
399                 case EVENT_TTY_MODE_SET:
400                     handleSetTTYModeResponse(msg);
401                     break;
402             }
403         }
404     };
405 
PhoneApp()406     public PhoneApp() {
407         sMe = this;
408     }
409 
410     @Override
onCreate()411     public void onCreate() {
412         if (VDBG) Log.v(LOG_TAG, "onCreate()...");
413 
414         ContentResolver resolver = getContentResolver();
415 
416         // Cache the "voice capable" flag.
417         // This flag currently comes from a resource (which is
418         // overrideable on a per-product basis):
419         sVoiceCapable =
420                 getResources().getBoolean(com.android.internal.R.bool.config_voice_capable);
421         // ...but this might eventually become a PackageManager "system
422         // feature" instead, in which case we'd do something like:
423         // sVoiceCapable =
424         //   getPackageManager().hasSystemFeature(PackageManager.FEATURE_TELEPHONY_VOICE_CALLS);
425 
426         if (phone == null) {
427             // Initialize the telephony framework
428             PhoneFactory.makeDefaultPhones(this);
429 
430             // Get the default phone
431             phone = PhoneFactory.getDefaultPhone();
432 
433             mCM = CallManager.getInstance();
434             mCM.registerPhone(phone);
435 
436             // Create the NotificationMgr singleton, which is used to display
437             // status bar icons and control other status bar behavior.
438             notificationMgr = NotificationMgr.init(this);
439 
440             phoneMgr = PhoneInterfaceManager.init(this, phone);
441 
442             mHandler.sendEmptyMessage(EVENT_START_SIP_SERVICE);
443 
444             int phoneType = phone.getPhoneType();
445 
446             if (phoneType == Phone.PHONE_TYPE_CDMA) {
447                 // Create an instance of CdmaPhoneCallState and initialize it to IDLE
448                 cdmaPhoneCallState = new CdmaPhoneCallState();
449                 cdmaPhoneCallState.CdmaPhoneCallStateInit();
450             }
451 
452             if (BluetoothAdapter.getDefaultAdapter() != null) {
453                 // Start BluetoothHandsree even if device is not voice capable.
454                 // The device can still support VOIP.
455                 mBtHandsfree = BluetoothHandsfree.init(this, mCM);
456                 startService(new Intent(this, BluetoothHeadsetService.class));
457             } else {
458                 // Device is not bluetooth capable
459                 mBtHandsfree = null;
460             }
461 
462             ringer = Ringer.init(this);
463 
464             // before registering for phone state changes
465             PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
466             mWakeLock = pm.newWakeLock(PowerManager.FULL_WAKE_LOCK
467                     | PowerManager.ACQUIRE_CAUSES_WAKEUP,
468                     LOG_TAG);
469             // lock used to keep the processor awake, when we don't care for the display.
470             mPartialWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK
471                     | PowerManager.ON_AFTER_RELEASE, LOG_TAG);
472             // Wake lock used to control proximity sensor behavior.
473             if ((pm.getSupportedWakeLockFlags()
474                  & PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK) != 0x0) {
475                 mProximityWakeLock =
476                         pm.newWakeLock(PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK, LOG_TAG);
477             }
478             if (DBG) Log.d(LOG_TAG, "onCreate: mProximityWakeLock: " + mProximityWakeLock);
479 
480             // create mAccelerometerListener only if we are using the proximity sensor
481             if (proximitySensorModeEnabled()) {
482                 mAccelerometerListener = new AccelerometerListener(this, this);
483             }
484 
485             mKeyguardManager = (KeyguardManager) getSystemService(Context.KEYGUARD_SERVICE);
486 
487             // get a handle to the service so that we can use it later when we
488             // want to set the poke lock.
489             mPowerManagerService = IPowerManager.Stub.asInterface(
490                     ServiceManager.getService("power"));
491 
492             // Create the CallController singleton, which is the interface
493             // to the telephony layer for user-initiated telephony functionality
494             // (like making outgoing calls.)
495             callController = CallController.init(this);
496             // ...and also the InCallUiState instance, used by the CallController to
497             // keep track of some "persistent state" of the in-call UI.
498             inCallUiState = InCallUiState.init(this);
499 
500             // Create the CallNotifer singleton, which handles
501             // asynchronous events from the telephony layer (like
502             // launching the incoming-call UI when an incoming call comes
503             // in.)
504             notifier = CallNotifier.init(this, phone, ringer, mBtHandsfree, new CallLogAsync());
505 
506             // register for ICC status
507             IccCard sim = phone.getIccCard();
508             if (sim != null) {
509                 if (VDBG) Log.v(LOG_TAG, "register for ICC status");
510                 sim.registerForNetworkLocked(mHandler, EVENT_SIM_NETWORK_LOCKED, null);
511             }
512 
513             // register for MMI/USSD
514             mCM.registerForMmiComplete(mHandler, MMI_COMPLETE, null);
515 
516             // register connection tracking to PhoneUtils
517             PhoneUtils.initializeConnectionHandler(mCM);
518 
519             // Read platform settings for TTY feature
520             mTtyEnabled = getResources().getBoolean(R.bool.tty_enabled);
521 
522             // Register for misc other intent broadcasts.
523             IntentFilter intentFilter =
524                     new IntentFilter(Intent.ACTION_AIRPLANE_MODE_CHANGED);
525             intentFilter.addAction(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED);
526             intentFilter.addAction(BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED);
527             intentFilter.addAction(TelephonyIntents.ACTION_ANY_DATA_CONNECTION_STATE_CHANGED);
528             intentFilter.addAction(Intent.ACTION_HEADSET_PLUG);
529             intentFilter.addAction(Intent.ACTION_DOCK_EVENT);
530             intentFilter.addAction(Intent.ACTION_BATTERY_LOW);
531             intentFilter.addAction(TelephonyIntents.ACTION_SIM_STATE_CHANGED);
532             intentFilter.addAction(TelephonyIntents.ACTION_RADIO_TECHNOLOGY_CHANGED);
533             intentFilter.addAction(TelephonyIntents.ACTION_SERVICE_STATE_CHANGED);
534             intentFilter.addAction(TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED);
535             if (mTtyEnabled) {
536                 intentFilter.addAction(TtyIntent.TTY_PREFERRED_MODE_CHANGE_ACTION);
537             }
538             intentFilter.addAction(AudioManager.RINGER_MODE_CHANGED_ACTION);
539             registerReceiver(mReceiver, intentFilter);
540 
541             // Use a separate receiver for ACTION_MEDIA_BUTTON broadcasts,
542             // since we need to manually adjust its priority (to make sure
543             // we get these intents *before* the media player.)
544             IntentFilter mediaButtonIntentFilter =
545                     new IntentFilter(Intent.ACTION_MEDIA_BUTTON);
546             //
547             // Make sure we're higher priority than the media player's
548             // MediaButtonIntentReceiver (which currently has the default
549             // priority of zero; see apps/Music/AndroidManifest.xml.)
550             mediaButtonIntentFilter.setPriority(1);
551             //
552             registerReceiver(mMediaButtonReceiver, mediaButtonIntentFilter);
553 
554             //set the default values for the preferences in the phone.
555             PreferenceManager.setDefaultValues(this, R.xml.network_setting, false);
556 
557             PreferenceManager.setDefaultValues(this, R.xml.call_feature_setting, false);
558 
559             // Make sure the audio mode (along with some
560             // audio-mode-related state of our own) is initialized
561             // correctly, given the current state of the phone.
562             PhoneUtils.setAudioMode(mCM);
563         }
564 
565         if (TelephonyCapabilities.supportsOtasp(phone)) {
566             cdmaOtaProvisionData = new OtaUtils.CdmaOtaProvisionData();
567             cdmaOtaConfigData = new OtaUtils.CdmaOtaConfigData();
568             cdmaOtaScreenState = new OtaUtils.CdmaOtaScreenState();
569             cdmaOtaInCallScreenUiState = new OtaUtils.CdmaOtaInCallScreenUiState();
570         }
571 
572         // XXX pre-load the SimProvider so that it's ready
573         resolver.getType(Uri.parse("content://icc/adn"));
574 
575         // start with the default value to set the mute state.
576         mShouldRestoreMuteOnInCallResume = false;
577 
578         // TODO: Register for Cdma Information Records
579         // phone.registerCdmaInformationRecord(mHandler, EVENT_UNSOL_CDMA_INFO_RECORD, null);
580 
581         // Read TTY settings and store it into BP NV.
582         // AP owns (i.e. stores) the TTY setting in AP settings database and pushes the setting
583         // to BP at power up (BP does not need to make the TTY setting persistent storage).
584         // This way, there is a single owner (i.e AP) for the TTY setting in the phone.
585         if (mTtyEnabled) {
586             mPreferredTtyMode = android.provider.Settings.Secure.getInt(
587                     phone.getContext().getContentResolver(),
588                     android.provider.Settings.Secure.PREFERRED_TTY_MODE,
589                     Phone.TTY_MODE_OFF);
590             mHandler.sendMessage(mHandler.obtainMessage(EVENT_TTY_PREFERRED_MODE_CHANGED, 0));
591         }
592         // Read HAC settings and configure audio hardware
593         if (getResources().getBoolean(R.bool.hac_enabled)) {
594             int hac = android.provider.Settings.System.getInt(phone.getContext().getContentResolver(),
595                                                               android.provider.Settings.System.HEARING_AID,
596                                                               0);
597             AudioManager audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
598             audioManager.setParameter(CallFeaturesSetting.HAC_KEY, hac != 0 ?
599                                       CallFeaturesSetting.HAC_VAL_ON :
600                                       CallFeaturesSetting.HAC_VAL_OFF);
601         }
602    }
603 
604     @Override
onConfigurationChanged(Configuration newConfig)605     public void onConfigurationChanged(Configuration newConfig) {
606         if (newConfig.hardKeyboardHidden == Configuration.HARDKEYBOARDHIDDEN_NO) {
607             mIsHardKeyboardOpen = true;
608         } else {
609             mIsHardKeyboardOpen = false;
610         }
611 
612         // Update the Proximity sensor based on keyboard state
613         updateProximitySensorMode(mCM.getState());
614         super.onConfigurationChanged(newConfig);
615     }
616 
617     /**
618      * Returns the singleton instance of the PhoneApp.
619      */
getInstance()620     static PhoneApp getInstance() {
621         return sMe;
622     }
623 
624     /**
625      * Returns the Phone associated with this instance
626      */
getPhone()627     static Phone getPhone() {
628         return getInstance().phone;
629     }
630 
getRinger()631     Ringer getRinger() {
632         return ringer;
633     }
634 
getBluetoothHandsfree()635     BluetoothHandsfree getBluetoothHandsfree() {
636         return mBtHandsfree;
637     }
638 
639     /**
640      * Returns an Intent that can be used to go to the "Call log"
641      * UI (aka CallLogActivity) in the Contacts app.
642      *
643      * Watch out: there's no guarantee that the system has any activity to
644      * handle this intent.  (In particular there may be no "Call log" at
645      * all on on non-voice-capable devices.)
646      */
createCallLogIntent()647     /* package */ static Intent createCallLogIntent() {
648         Intent intent = new Intent(Intent.ACTION_VIEW, null);
649         intent.setType("vnd.android.cursor.dir/calls");
650         return intent;
651     }
652 
653     /**
654      * Return an Intent that can be used to bring up the in-call screen.
655      *
656      * This intent can only be used from within the Phone app, since the
657      * InCallScreen is not exported from our AndroidManifest.
658      */
createInCallIntent()659     /* package */ static Intent createInCallIntent() {
660         Intent intent = new Intent(Intent.ACTION_MAIN, null);
661         intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
662                 | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
663                 | Intent.FLAG_ACTIVITY_NO_USER_ACTION);
664         intent.setClassName("com.android.phone", getCallScreenClassName());
665         return intent;
666     }
667 
668     /**
669      * Variation of createInCallIntent() that also specifies whether the
670      * DTMF dialpad should be initially visible when the InCallScreen
671      * comes up.
672      */
createInCallIntent(boolean showDialpad)673     /* package */ static Intent createInCallIntent(boolean showDialpad) {
674         Intent intent = createInCallIntent();
675         intent.putExtra(InCallScreen.SHOW_DIALPAD_EXTRA, showDialpad);
676         return intent;
677     }
678 
679     // TODO(InCallScreen redesign): This should be made private once
680     // we fix PhoneInterfaceManager.java to *not* manually launch
681     // the InCallScreen from its call() method.
getCallScreenClassName()682     static String getCallScreenClassName() {
683         return InCallScreen.class.getName();
684     }
685 
686     /**
687      * Starts the InCallScreen Activity.
688      */
displayCallScreen()689     /* package */ void displayCallScreen() {
690         if (VDBG) Log.d(LOG_TAG, "displayCallScreen()...");
691 
692         // On non-voice-capable devices we shouldn't ever be trying to
693         // bring up the InCallScreen in the first place.
694         if (!sVoiceCapable) {
695             Log.w(LOG_TAG, "displayCallScreen() not allowed: non-voice-capable device",
696                   new Throwable("stack dump"));  // Include a stack trace since this warning
697                                                  // indicates a bug in our caller
698             return;
699         }
700 
701         try {
702             startActivity(createInCallIntent());
703         } catch (ActivityNotFoundException e) {
704             // It's possible that the in-call UI might not exist (like on
705             // non-voice-capable devices), so don't crash if someone
706             // accidentally tries to bring it up...
707             Log.w(LOG_TAG, "displayCallScreen: transition to InCallScreen failed: " + e);
708         }
709         Profiler.callScreenRequested();
710     }
711 
isSimPinEnabled()712     boolean isSimPinEnabled() {
713         return mIsSimPinEnabled;
714     }
715 
authenticateAgainstCachedSimPin(String pin)716     boolean authenticateAgainstCachedSimPin(String pin) {
717         return (mCachedSimPin != null && mCachedSimPin.equals(pin));
718     }
719 
setCachedSimPin(String pin)720     void setCachedSimPin(String pin) {
721         mCachedSimPin = pin;
722     }
723 
setInCallScreenInstance(InCallScreen inCallScreen)724     void setInCallScreenInstance(InCallScreen inCallScreen) {
725         mInCallScreen = inCallScreen;
726     }
727 
728     /**
729      * @return true if the in-call UI is running as the foreground
730      * activity.  (In other words, from the perspective of the
731      * InCallScreen activity, return true between onResume() and
732      * onPause().)
733      *
734      * Note this method will return false if the screen is currently off,
735      * even if the InCallScreen *was* in the foreground just before the
736      * screen turned off.  (This is because the foreground activity is
737      * always "paused" while the screen is off.)
738      */
isShowingCallScreen()739     boolean isShowingCallScreen() {
740         if (mInCallScreen == null) return false;
741         return mInCallScreen.isForegroundActivity();
742     }
743 
744     /**
745      * Dismisses the in-call UI.
746      *
747      * This also ensures that you won't be able to get back to the in-call
748      * UI via the BACK button (since this call removes the InCallScreen
749      * from the activity history.)
750      * For OTA Call, it call InCallScreen api to handle OTA Call End scenario
751      * to display OTA Call End screen.
752      */
dismissCallScreen()753     /* package */ void dismissCallScreen() {
754         if (mInCallScreen != null) {
755             if ((TelephonyCapabilities.supportsOtasp(phone)) &&
756                     (mInCallScreen.isOtaCallInActiveState()
757                     || mInCallScreen.isOtaCallInEndState()
758                     || ((cdmaOtaScreenState != null)
759                     && (cdmaOtaScreenState.otaScreenState
760                             != CdmaOtaScreenState.OtaScreenState.OTA_STATUS_UNDEFINED)))) {
761                 // TODO: During OTA Call, display should not become dark to
762                 // allow user to see OTA UI update. Phone app needs to hold
763                 // a SCREEN_DIM_WAKE_LOCK wake lock during the entire OTA call.
764                 wakeUpScreen();
765                 // If InCallScreen is not in foreground we resume it to show the OTA call end screen
766                 // Fire off the InCallScreen intent
767                 displayCallScreen();
768 
769                 mInCallScreen.handleOtaCallEnd();
770                 return;
771             } else {
772                 mInCallScreen.finish();
773             }
774         }
775     }
776 
777     /**
778      * Handles OTASP-related events from the telephony layer.
779      *
780      * While an OTASP call is active, the CallNotifier forwards
781      * OTASP-related telephony events to this method.
782      */
handleOtaspEvent(Message msg)783     void handleOtaspEvent(Message msg) {
784         if (DBG) Log.d(LOG_TAG, "handleOtaspEvent(message " + msg + ")...");
785 
786         if (otaUtils == null) {
787             // We shouldn't be getting OTASP events without ever
788             // having started the OTASP call in the first place!
789             Log.w(LOG_TAG, "handleOtaEvents: got an event but otaUtils is null! "
790                   + "message = " + msg);
791             return;
792         }
793 
794         otaUtils.onOtaProvisionStatusChanged((AsyncResult) msg.obj);
795     }
796 
797     /**
798      * Similarly, handle the disconnect event of an OTASP call
799      * by forwarding it to the OtaUtils instance.
800      */
handleOtaspDisconnect()801     /* package */ void handleOtaspDisconnect() {
802         if (DBG) Log.d(LOG_TAG, "handleOtaspDisconnect()...");
803 
804         if (otaUtils == null) {
805             // We shouldn't be getting OTASP events without ever
806             // having started the OTASP call in the first place!
807             Log.w(LOG_TAG, "handleOtaspDisconnect: otaUtils is null!");
808             return;
809         }
810 
811         otaUtils.onOtaspDisconnect();
812     }
813 
814     /**
815      * Sets the activity responsible for un-PUK-blocking the device
816      * so that we may close it when we receive a positive result.
817      * mPUKEntryActivity is also used to indicate to the device that
818      * we are trying to un-PUK-lock the phone. In other words, iff
819      * it is NOT null, then we are trying to unlock and waiting for
820      * the SIM to move to READY state.
821      *
822      * @param activity is the activity to close when PUK has
823      * finished unlocking. Can be set to null to indicate the unlock
824      * or SIM READYing process is over.
825      */
setPukEntryActivity(Activity activity)826     void setPukEntryActivity(Activity activity) {
827         mPUKEntryActivity = activity;
828     }
829 
getPUKEntryActivity()830     Activity getPUKEntryActivity() {
831         return mPUKEntryActivity;
832     }
833 
834     /**
835      * Sets the dialog responsible for notifying the user of un-PUK-
836      * blocking - SIM READYing progress, so that we may dismiss it
837      * when we receive a positive result.
838      *
839      * @param dialog indicates the progress dialog informing the user
840      * of the state of the device.  Dismissed upon completion of
841      * READYing process
842      */
setPukEntryProgressDialog(ProgressDialog dialog)843     void setPukEntryProgressDialog(ProgressDialog dialog) {
844         mPUKEntryProgressDialog = dialog;
845     }
846 
getPUKEntryProgressDialog()847     ProgressDialog getPUKEntryProgressDialog() {
848         return mPUKEntryProgressDialog;
849     }
850 
851     /**
852      * Controls how quickly the screen times out.
853      *
854      * The poke lock controls how long it takes before the screen powers
855      * down, and therefore has no immediate effect when the current
856      * WakeState (see {@link PhoneApp#requestWakeState}) is FULL.
857      * If we're in a state where the screen *is* allowed to turn off,
858      * though, the poke lock will determine the timeout interval (long or
859      * short).
860      *
861      * @param shortPokeLock tells the device the timeout duration to use
862      * before going to sleep
863      * {@link com.android.server.PowerManagerService#SHORT_KEYLIGHT_DELAY}.
864      */
setScreenTimeout(ScreenTimeoutDuration duration)865     /* package */ void setScreenTimeout(ScreenTimeoutDuration duration) {
866         if (VDBG) Log.d(LOG_TAG, "setScreenTimeout(" + duration + ")...");
867 
868         // make sure we don't set the poke lock repeatedly so that we
869         // avoid triggering the userActivity calls in
870         // PowerManagerService.setPokeLock().
871         if (duration == mScreenTimeoutDuration) {
872             return;
873         }
874         // stick with default timeout if we are using the proximity sensor
875         if (proximitySensorModeEnabled()) {
876             return;
877         }
878         mScreenTimeoutDuration = duration;
879         updatePokeLock();
880     }
881 
882     /**
883      * Update the state of the poke lock held by the phone app,
884      * based on the current desired screen timeout and the
885      * current "ignore user activity on touch" flag.
886      */
updatePokeLock()887     private void updatePokeLock() {
888         // This is kind of convoluted, but the basic thing to remember is
889         // that the poke lock just sends a message to the screen to tell
890         // it to stay on for a while.
891         // The default is 0, for a long timeout and should be set that way
892         // when we are heading back into a the keyguard / screen off
893         // state, and also when we're trying to keep the screen alive
894         // while ringing.  We'll also want to ignore the cheek events
895         // regardless of the timeout duration.
896         // The short timeout is really used whenever we want to give up
897         // the screen lock, such as when we're in call.
898         int pokeLockSetting = 0;
899         switch (mScreenTimeoutDuration) {
900             case SHORT:
901                 // Set the poke lock to timeout the display after a short
902                 // timeout (5s). This ensures that the screen goes to sleep
903                 // as soon as acceptably possible after we the wake lock
904                 // has been released.
905                 pokeLockSetting |= LocalPowerManager.POKE_LOCK_SHORT_TIMEOUT;
906                 break;
907 
908             case MEDIUM:
909                 // Set the poke lock to timeout the display after a medium
910                 // timeout (15s). This ensures that the screen goes to sleep
911                 // as soon as acceptably possible after we the wake lock
912                 // has been released.
913                 pokeLockSetting |= LocalPowerManager.POKE_LOCK_MEDIUM_TIMEOUT;
914                 break;
915 
916             case DEFAULT:
917             default:
918                 // set the poke lock to timeout the display after a long
919                 // delay by default.
920                 // TODO: it may be nice to be able to disable cheek presses
921                 // for long poke locks (emergency dialer, for instance).
922                 break;
923         }
924 
925         if (mIgnoreTouchUserActivity) {
926             pokeLockSetting |= LocalPowerManager.POKE_LOCK_IGNORE_TOUCH_EVENTS;
927         }
928 
929         // Send the request
930         try {
931             mPowerManagerService.setPokeLock(pokeLockSetting, mPokeLockToken, LOG_TAG);
932         } catch (RemoteException e) {
933             Log.w(LOG_TAG, "mPowerManagerService.setPokeLock() failed: " + e);
934         }
935     }
936 
937     /**
938      * Controls whether or not the screen is allowed to sleep.
939      *
940      * Once sleep is allowed (WakeState is SLEEP), it will rely on the
941      * settings for the poke lock to determine when to timeout and let
942      * the device sleep {@link PhoneApp#setScreenTimeout}.
943      *
944      * @param ws tells the device to how to wake.
945      */
requestWakeState(WakeState ws)946     /* package */ void requestWakeState(WakeState ws) {
947         if (VDBG) Log.d(LOG_TAG, "requestWakeState(" + ws + ")...");
948         synchronized (this) {
949             if (mWakeState != ws) {
950                 switch (ws) {
951                     case PARTIAL:
952                         // acquire the processor wake lock, and release the FULL
953                         // lock if it is being held.
954                         mPartialWakeLock.acquire();
955                         if (mWakeLock.isHeld()) {
956                             mWakeLock.release();
957                         }
958                         break;
959                     case FULL:
960                         // acquire the full wake lock, and release the PARTIAL
961                         // lock if it is being held.
962                         mWakeLock.acquire();
963                         if (mPartialWakeLock.isHeld()) {
964                             mPartialWakeLock.release();
965                         }
966                         break;
967                     case SLEEP:
968                     default:
969                         // release both the PARTIAL and FULL locks.
970                         if (mWakeLock.isHeld()) {
971                             mWakeLock.release();
972                         }
973                         if (mPartialWakeLock.isHeld()) {
974                             mPartialWakeLock.release();
975                         }
976                         break;
977                 }
978                 mWakeState = ws;
979             }
980         }
981     }
982 
983     /**
984      * If we are not currently keeping the screen on, then poke the power
985      * manager to wake up the screen for the user activity timeout duration.
986      */
wakeUpScreen()987     /* package */ void wakeUpScreen() {
988         synchronized (this) {
989             if (mWakeState == WakeState.SLEEP) {
990                 if (DBG) Log.d(LOG_TAG, "pulse screen lock");
991                 try {
992                     mPowerManagerService.userActivityWithForce(SystemClock.uptimeMillis(), false, true);
993                 } catch (RemoteException ex) {
994                     // Ignore -- the system process is dead.
995                 }
996             }
997         }
998     }
999 
1000     /**
1001      * Sets the wake state and screen timeout based on the current state
1002      * of the phone, and the current state of the in-call UI.
1003      *
1004      * This method is a "UI Policy" wrapper around
1005      * {@link PhoneApp#requestWakeState} and {@link PhoneApp#setScreenTimeout}.
1006      *
1007      * It's safe to call this method regardless of the state of the Phone
1008      * (e.g. whether or not it's idle), and regardless of the state of the
1009      * Phone UI (e.g. whether or not the InCallScreen is active.)
1010      */
updateWakeState()1011     /* package */ void updateWakeState() {
1012         Phone.State state = mCM.getState();
1013 
1014         // True if the in-call UI is the foreground activity.
1015         // (Note this will be false if the screen is currently off,
1016         // since in that case *no* activity is in the foreground.)
1017         boolean isShowingCallScreen = isShowingCallScreen();
1018 
1019         // True if the InCallScreen's DTMF dialer is currently opened.
1020         // (Note this does NOT imply whether or not the InCallScreen
1021         // itself is visible.)
1022         boolean isDialerOpened = (mInCallScreen != null) && mInCallScreen.isDialerOpened();
1023 
1024         // True if the speakerphone is in use.  (If so, we *always* use
1025         // the default timeout.  Since the user is obviously not holding
1026         // the phone up to his/her face, we don't need to worry about
1027         // false touches, and thus don't need to turn the screen off so
1028         // aggressively.)
1029         // Note that we need to make a fresh call to this method any
1030         // time the speaker state changes.  (That happens in
1031         // PhoneUtils.turnOnSpeaker().)
1032         boolean isSpeakerInUse = (state == Phone.State.OFFHOOK) && PhoneUtils.isSpeakerOn(this);
1033 
1034         // TODO (bug 1440854): The screen timeout *might* also need to
1035         // depend on the bluetooth state, but this isn't as clear-cut as
1036         // the speaker state (since while using BT it's common for the
1037         // user to put the phone straight into a pocket, in which case the
1038         // timeout should probably still be short.)
1039 
1040         if (DBG) Log.d(LOG_TAG, "updateWakeState: callscreen " + isShowingCallScreen
1041                        + ", dialer " + isDialerOpened
1042                        + ", speaker " + isSpeakerInUse + "...");
1043 
1044         //
1045         // (1) Set the screen timeout.
1046         //
1047         // Note that the "screen timeout" value we determine here is
1048         // meaningless if the screen is forced on (see (2) below.)
1049         //
1050 
1051         // Historical note: In froyo and earlier, we checked here for a special
1052         // case: the in-call UI being active, the speaker off, and the DTMF dialpad
1053         // not visible.  In that case, with no touchable UI onscreen at all (for
1054         // non-prox-sensor devices at least), we could assume the user was probably
1055         // holding the phone up to their face and *not* actually looking at the
1056         // screen.  So we'd switch to a special screen timeout value
1057         // (ScreenTimeoutDuration.MEDIUM), purely to save battery life.
1058         //
1059         // On current devices, we can rely on the proximity sensor to turn the
1060         // screen off in this case, so we use the system-wide default timeout
1061         // unconditionally.
1062         setScreenTimeout(ScreenTimeoutDuration.DEFAULT);
1063 
1064         //
1065         // (2) Decide whether to force the screen on or not.
1066         //
1067         // Force the screen to be on if the phone is ringing or dialing,
1068         // or if we're displaying the "Call ended" UI for a connection in
1069         // the "disconnected" state.
1070         //
1071         boolean isRinging = (state == Phone.State.RINGING);
1072         boolean isDialing = (phone.getForegroundCall().getState() == Call.State.DIALING);
1073         boolean showingDisconnectedConnection =
1074                 PhoneUtils.hasDisconnectedConnections(phone) && isShowingCallScreen;
1075         boolean keepScreenOn = isRinging || isDialing || showingDisconnectedConnection;
1076         if (DBG) Log.d(LOG_TAG, "updateWakeState: keepScreenOn = " + keepScreenOn
1077                        + " (isRinging " + isRinging
1078                        + ", isDialing " + isDialing
1079                        + ", showingDisc " + showingDisconnectedConnection + ")");
1080         // keepScreenOn == true means we'll hold a full wake lock:
1081         requestWakeState(keepScreenOn ? WakeState.FULL : WakeState.SLEEP);
1082     }
1083 
1084     /**
1085      * Wrapper around the PowerManagerService.preventScreenOn() API.
1086      * This allows the in-call UI to prevent the screen from turning on
1087      * even if a subsequent call to updateWakeState() causes us to acquire
1088      * a full wake lock.
1089      */
preventScreenOn(boolean prevent)1090     /* package */ void preventScreenOn(boolean prevent) {
1091         if (VDBG) Log.d(LOG_TAG, "- preventScreenOn(" + prevent + ")...");
1092         try {
1093             mPowerManagerService.preventScreenOn(prevent);
1094         } catch (RemoteException e) {
1095             Log.w(LOG_TAG, "mPowerManagerService.preventScreenOn() failed: " + e);
1096         }
1097     }
1098 
1099     /**
1100      * Sets or clears the flag that tells the PowerManager that touch
1101      * (and cheek) events should NOT be considered "user activity".
1102      *
1103      * Since the in-call UI is totally insensitive to touch in most
1104      * states, we set this flag whenever the InCallScreen is in the
1105      * foreground.  (Otherwise, repeated unintentional touches could
1106      * prevent the device from going to sleep.)
1107      *
1108      * There *are* some some touch events that really do count as user
1109      * activity, though.  For those, we need to manually poke the
1110      * PowerManager's userActivity method; see pokeUserActivity().
1111      */
setIgnoreTouchUserActivity(boolean ignore)1112     /* package */ void setIgnoreTouchUserActivity(boolean ignore) {
1113         if (VDBG) Log.d(LOG_TAG, "setIgnoreTouchUserActivity(" + ignore + ")...");
1114         mIgnoreTouchUserActivity = ignore;
1115         updatePokeLock();
1116     }
1117 
1118     /**
1119      * Manually pokes the PowerManager's userActivity method.  Since we
1120      * hold the POKE_LOCK_IGNORE_TOUCH_EVENTS poke lock while
1121      * the InCallScreen is active, we need to do this for touch events
1122      * that really do count as user activity (like pressing any
1123      * onscreen UI elements.)
1124      */
pokeUserActivity()1125     /* package */ void pokeUserActivity() {
1126         if (VDBG) Log.d(LOG_TAG, "pokeUserActivity()...");
1127         try {
1128             mPowerManagerService.userActivity(SystemClock.uptimeMillis(), false);
1129         } catch (RemoteException e) {
1130             Log.w(LOG_TAG, "mPowerManagerService.userActivity() failed: " + e);
1131         }
1132     }
1133 
1134     /**
1135      * Set when a new outgoing call is beginning, so we can update
1136      * the proximity sensor state.
1137      * Cleared when the InCallScreen is no longer in the foreground,
1138      * in case the call fails without changing the telephony state.
1139      */
setBeginningCall(boolean beginning)1140     /* package */ void setBeginningCall(boolean beginning) {
1141         // Note that we are beginning a new call, for proximity sensor support
1142         mBeginningCall = beginning;
1143         // Update the Proximity sensor based on mBeginningCall state
1144         updateProximitySensorMode(mCM.getState());
1145     }
1146 
1147     /**
1148      * Updates the wake lock used to control proximity sensor behavior,
1149      * based on the current state of the phone.  This method is called
1150      * from the CallNotifier on any phone state change.
1151      *
1152      * On devices that have a proximity sensor, to avoid false touches
1153      * during a call, we hold a PROXIMITY_SCREEN_OFF_WAKE_LOCK wake lock
1154      * whenever the phone is off hook.  (When held, that wake lock causes
1155      * the screen to turn off automatically when the sensor detects an
1156      * object close to the screen.)
1157      *
1158      * This method is a no-op for devices that don't have a proximity
1159      * sensor.
1160      *
1161      * Note this method doesn't care if the InCallScreen is the foreground
1162      * activity or not.  That's because we want the proximity sensor to be
1163      * enabled any time the phone is in use, to avoid false cheek events
1164      * for whatever app you happen to be running.
1165      *
1166      * Proximity wake lock will *not* be held if any one of the
1167      * conditions is true while on a call:
1168      * 1) If the audio is routed via Bluetooth
1169      * 2) If a wired headset is connected
1170      * 3) if the speaker is ON
1171      * 4) If the slider is open(i.e. the hardkeyboard is *not* hidden)
1172      *
1173      * @param state current state of the phone (see {@link Phone#State})
1174      */
updateProximitySensorMode(Phone.State state)1175     /* package */ void updateProximitySensorMode(Phone.State state) {
1176         if (VDBG) Log.d(LOG_TAG, "updateProximitySensorMode: state = " + state);
1177 
1178         if (proximitySensorModeEnabled()) {
1179             synchronized (mProximityWakeLock) {
1180                 // turn proximity sensor off and turn screen on immediately if
1181                 // we are using a headset, the keyboard is open, or the device
1182                 // is being held in a horizontal position.
1183                 boolean screenOnImmediately = (isHeadsetPlugged()
1184                             || PhoneUtils.isSpeakerOn(this)
1185                             || ((mBtHandsfree != null) && mBtHandsfree.isAudioOn())
1186                             || mIsHardKeyboardOpen);
1187                 // We do not keep the screen off when we are horizontal, but we do not force it
1188                 // on when we become horizontal until the proximity sensor goes negative.
1189                 boolean horizontal = (mOrientation == AccelerometerListener.ORIENTATION_HORIZONTAL);
1190 
1191                 if (((state == Phone.State.OFFHOOK) || mBeginningCall) &&
1192                         !screenOnImmediately && !horizontal) {
1193                     // Phone is in use!  Arrange for the screen to turn off
1194                     // automatically when the sensor detects a close object.
1195                     if (!mProximityWakeLock.isHeld()) {
1196                         if (DBG) Log.d(LOG_TAG, "updateProximitySensorMode: acquiring...");
1197                         mProximityWakeLock.acquire();
1198                     } else {
1199                         if (VDBG) Log.d(LOG_TAG, "updateProximitySensorMode: lock already held.");
1200                     }
1201                 } else {
1202                     // Phone is either idle, or ringing.  We don't want any
1203                     // special proximity sensor behavior in either case.
1204                     if (mProximityWakeLock.isHeld()) {
1205                         if (DBG) Log.d(LOG_TAG, "updateProximitySensorMode: releasing...");
1206                         // Wait until user has moved the phone away from his head if we are
1207                         // releasing due to the phone call ending.
1208                         // Qtherwise, turn screen on immediately
1209                         int flags =
1210                             (screenOnImmediately ? 0 : PowerManager.WAIT_FOR_PROXIMITY_NEGATIVE);
1211                         mProximityWakeLock.release(flags);
1212                     } else {
1213                         if (VDBG) {
1214                             Log.d(LOG_TAG, "updateProximitySensorMode: lock already released.");
1215                         }
1216                     }
1217                 }
1218             }
1219         }
1220     }
1221 
orientationChanged(int orientation)1222     public void orientationChanged(int orientation) {
1223         mOrientation = orientation;
1224         updateProximitySensorMode(mCM.getState());
1225     }
1226 
1227     /**
1228      * Notifies the phone app when the phone state changes.
1229      * Currently used only for proximity sensor support.
1230      */
updatePhoneState(Phone.State state)1231     /* package */ void updatePhoneState(Phone.State state) {
1232         if (state != mLastPhoneState) {
1233             mLastPhoneState = state;
1234             updateProximitySensorMode(state);
1235             if (mAccelerometerListener != null) {
1236                 // use accelerometer to augment proximity sensor when in call
1237                 mOrientation = AccelerometerListener.ORIENTATION_UNKNOWN;
1238                 mAccelerometerListener.enable(state == Phone.State.OFFHOOK);
1239             }
1240             // clear our beginning call flag
1241             mBeginningCall = false;
1242             // While we are in call, the in-call screen should dismiss the keyguard.
1243             // This allows the user to press Home to go directly home without going through
1244             // an insecure lock screen.
1245             // But we do not want to do this if there is no active call so we do not
1246             // bypass the keyguard if the call is not answered or declined.
1247             if (mInCallScreen != null) {
1248                 mInCallScreen.updateKeyguardPolicy(state == Phone.State.OFFHOOK);
1249             }
1250         }
1251     }
1252 
getPhoneState()1253     /* package */ Phone.State getPhoneState() {
1254         return mLastPhoneState;
1255     }
1256 
1257     /**
1258      * @return true if this device supports the "proximity sensor
1259      * auto-lock" feature while in-call (see updateProximitySensorMode()).
1260      */
proximitySensorModeEnabled()1261     /* package */ boolean proximitySensorModeEnabled() {
1262         return (mProximityWakeLock != null);
1263     }
1264 
getKeyguardManager()1265     KeyguardManager getKeyguardManager() {
1266         return mKeyguardManager;
1267     }
1268 
onMMIComplete(AsyncResult r)1269     private void onMMIComplete(AsyncResult r) {
1270         if (VDBG) Log.d(LOG_TAG, "onMMIComplete()...");
1271         MmiCode mmiCode = (MmiCode) r.result;
1272         PhoneUtils.displayMMIComplete(phone, getInstance(), mmiCode, null, null);
1273     }
1274 
initForNewRadioTechnology()1275     private void initForNewRadioTechnology() {
1276         if (DBG) Log.d(LOG_TAG, "initForNewRadioTechnology...");
1277 
1278          if (phone.getPhoneType() == Phone.PHONE_TYPE_CDMA) {
1279             // Create an instance of CdmaPhoneCallState and initialize it to IDLE
1280             cdmaPhoneCallState = new CdmaPhoneCallState();
1281             cdmaPhoneCallState.CdmaPhoneCallStateInit();
1282         }
1283         if (TelephonyCapabilities.supportsOtasp(phone)) {
1284             //create instances of CDMA OTA data classes
1285             if (cdmaOtaProvisionData == null) {
1286                 cdmaOtaProvisionData = new OtaUtils.CdmaOtaProvisionData();
1287             }
1288             if (cdmaOtaConfigData == null) {
1289                 cdmaOtaConfigData = new OtaUtils.CdmaOtaConfigData();
1290             }
1291             if (cdmaOtaScreenState == null) {
1292                 cdmaOtaScreenState = new OtaUtils.CdmaOtaScreenState();
1293             }
1294             if (cdmaOtaInCallScreenUiState == null) {
1295                 cdmaOtaInCallScreenUiState = new OtaUtils.CdmaOtaInCallScreenUiState();
1296             }
1297         } else {
1298             //Clean up OTA data in GSM/UMTS. It is valid only for CDMA
1299             clearOtaState();
1300         }
1301 
1302         ringer.updateRingerContextAfterRadioTechnologyChange(this.phone);
1303         notifier.updateCallNotifierRegistrationsAfterRadioTechnologyChange();
1304         if (mBtHandsfree != null) {
1305             mBtHandsfree.updateBtHandsfreeAfterRadioTechnologyChange();
1306         }
1307         if (mInCallScreen != null) {
1308             mInCallScreen.updateAfterRadioTechnologyChange();
1309         }
1310 
1311         // Update registration for ICC status after radio technology change
1312         IccCard sim = phone.getIccCard();
1313         if (sim != null) {
1314             if (DBG) Log.d(LOG_TAG, "Update registration for ICC status...");
1315 
1316             //Register all events new to the new active phone
1317             sim.registerForNetworkLocked(mHandler, EVENT_SIM_NETWORK_LOCKED, null);
1318         }
1319     }
1320 
1321 
1322     /**
1323      * @return true if a wired headset is currently plugged in.
1324      *
1325      * @see Intent.ACTION_HEADSET_PLUG (which we listen for in mReceiver.onReceive())
1326      */
isHeadsetPlugged()1327     boolean isHeadsetPlugged() {
1328         return mIsHeadsetPlugged;
1329     }
1330 
1331     /**
1332      * @return true if the onscreen UI should currently be showing the
1333      * special "bluetooth is active" indication in a couple of places (in
1334      * which UI elements turn blue and/or show the bluetooth logo.)
1335      *
1336      * This depends on the BluetoothHeadset state *and* the current
1337      * telephony state; see shouldShowBluetoothIndication().
1338      *
1339      * @see CallCard
1340      * @see NotificationMgr.updateInCallNotification
1341      */
showBluetoothIndication()1342     /* package */ boolean showBluetoothIndication() {
1343         return mShowBluetoothIndication;
1344     }
1345 
1346     /**
1347      * Recomputes the mShowBluetoothIndication flag based on the current
1348      * bluetooth state and current telephony state.
1349      *
1350      * This needs to be called any time the bluetooth headset state or the
1351      * telephony state changes.
1352      *
1353      * @param forceUiUpdate if true, force the UI elements that care
1354      *                      about this flag to update themselves.
1355      */
updateBluetoothIndication(boolean forceUiUpdate)1356     /* package */ void updateBluetoothIndication(boolean forceUiUpdate) {
1357         mShowBluetoothIndication = shouldShowBluetoothIndication(mBluetoothHeadsetState,
1358                                                                  mBluetoothHeadsetAudioState,
1359                                                                  mCM);
1360         if (forceUiUpdate) {
1361             // Post Handler messages to the various components that might
1362             // need to be refreshed based on the new state.
1363             if (isShowingCallScreen()) mInCallScreen.requestUpdateBluetoothIndication();
1364             if (DBG) Log.d (LOG_TAG, "- updating in-call notification for BT state change...");
1365             mHandler.sendEmptyMessage(EVENT_UPDATE_INCALL_NOTIFICATION);
1366         }
1367 
1368         // Update the Proximity sensor based on Bluetooth audio state
1369         updateProximitySensorMode(mCM.getState());
1370     }
1371 
1372     /**
1373      * UI policy helper function for the couple of places in the UI that
1374      * have some way of indicating that "bluetooth is in use."
1375      *
1376      * @return true if the onscreen UI should indicate that "bluetooth is in use",
1377      *         based on the specified bluetooth headset state, and the
1378      *         current state of the phone.
1379      * @see showBluetoothIndication()
1380      */
shouldShowBluetoothIndication(int bluetoothState, int bluetoothAudioState, CallManager cm)1381     private static boolean shouldShowBluetoothIndication(int bluetoothState,
1382                                                          int bluetoothAudioState,
1383                                                          CallManager cm) {
1384         // We want the UI to indicate that "bluetooth is in use" in two
1385         // slightly different cases:
1386         //
1387         // (a) The obvious case: if a bluetooth headset is currently in
1388         //     use for an ongoing call.
1389         //
1390         // (b) The not-so-obvious case: if an incoming call is ringing,
1391         //     and we expect that audio *will* be routed to a bluetooth
1392         //     headset once the call is answered.
1393 
1394         switch (cm.getState()) {
1395             case OFFHOOK:
1396                 // This covers normal active calls, and also the case if
1397                 // the foreground call is DIALING or ALERTING.  In this
1398                 // case, bluetooth is considered "active" if a headset
1399                 // is connected *and* audio is being routed to it.
1400                 return ((bluetoothState == BluetoothHeadset.STATE_CONNECTED)
1401                         && (bluetoothAudioState == BluetoothHeadset.STATE_AUDIO_CONNECTED));
1402 
1403             case RINGING:
1404                 // If an incoming call is ringing, we're *not* yet routing
1405                 // audio to the headset (since there's no in-call audio
1406                 // yet!)  In this case, if a bluetooth headset is
1407                 // connected at all, we assume that it'll become active
1408                 // once the user answers the phone.
1409                 return (bluetoothState == BluetoothHeadset.STATE_CONNECTED);
1410 
1411             default:  // Presumably IDLE
1412                 return false;
1413         }
1414     }
1415 
1416 
1417     /**
1418      * Receiver for misc intent broadcasts the Phone app cares about.
1419      */
1420     private class PhoneAppBroadcastReceiver extends BroadcastReceiver {
1421         @Override
onReceive(Context context, Intent intent)1422         public void onReceive(Context context, Intent intent) {
1423             String action = intent.getAction();
1424             if (action.equals(Intent.ACTION_AIRPLANE_MODE_CHANGED)) {
1425                 boolean enabled = System.getInt(getContentResolver(),
1426                         System.AIRPLANE_MODE_ON, 0) == 0;
1427                 phone.setRadioPower(enabled);
1428             } else if (action.equals(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED)) {
1429                 mBluetoothHeadsetState = intent.getIntExtra(BluetoothHeadset.EXTRA_STATE,
1430                                                           BluetoothHeadset.STATE_DISCONNECTED);
1431                 if (VDBG) Log.d(LOG_TAG, "mReceiver: HEADSET_STATE_CHANGED_ACTION");
1432                 if (VDBG) Log.d(LOG_TAG, "==> new state: " + mBluetoothHeadsetState);
1433                 updateBluetoothIndication(true);  // Also update any visible UI if necessary
1434             } else if (action.equals(BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED)) {
1435                 mBluetoothHeadsetAudioState =
1436                         intent.getIntExtra(BluetoothHeadset.EXTRA_STATE,
1437                                            BluetoothHeadset.STATE_AUDIO_DISCONNECTED);
1438                 if (VDBG) Log.d(LOG_TAG, "mReceiver: HEADSET_AUDIO_STATE_CHANGED_ACTION");
1439                 if (VDBG) Log.d(LOG_TAG, "==> new state: " + mBluetoothHeadsetAudioState);
1440                 updateBluetoothIndication(true);  // Also update any visible UI if necessary
1441             } else if (action.equals(TelephonyIntents.ACTION_ANY_DATA_CONNECTION_STATE_CHANGED)) {
1442                 if (VDBG) Log.d(LOG_TAG, "mReceiver: ACTION_ANY_DATA_CONNECTION_STATE_CHANGED");
1443                 if (VDBG) Log.d(LOG_TAG, "- state: " + intent.getStringExtra(Phone.STATE_KEY));
1444                 if (VDBG) Log.d(LOG_TAG, "- reason: "
1445                                 + intent.getStringExtra(Phone.STATE_CHANGE_REASON_KEY));
1446 
1447                 // The "data disconnected due to roaming" notification is
1448                 // visible if you've lost data connectivity because you're
1449                 // roaming and you have the "data roaming" feature turned off.
1450                 boolean disconnectedDueToRoaming = false;
1451                 if ("DISCONNECTED".equals(intent.getStringExtra(Phone.STATE_KEY))) {
1452                     String reason = intent.getStringExtra(Phone.STATE_CHANGE_REASON_KEY);
1453                     if (Phone.REASON_ROAMING_ON.equals(reason)) {
1454                         // We just lost our data connection, and the reason
1455                         // is that we started roaming.  This implies that
1456                         // the user has data roaming turned off.
1457                         disconnectedDueToRoaming = true;
1458                     }
1459                 }
1460                 mHandler.sendEmptyMessage(disconnectedDueToRoaming
1461                                           ? EVENT_DATA_ROAMING_DISCONNECTED
1462                                           : EVENT_DATA_ROAMING_OK);
1463             } else if (action.equals(Intent.ACTION_HEADSET_PLUG)) {
1464                 if (VDBG) Log.d(LOG_TAG, "mReceiver: ACTION_HEADSET_PLUG");
1465                 if (VDBG) Log.d(LOG_TAG, "    state: " + intent.getIntExtra("state", 0));
1466                 if (VDBG) Log.d(LOG_TAG, "    name: " + intent.getStringExtra("name"));
1467                 mIsHeadsetPlugged = (intent.getIntExtra("state", 0) == 1);
1468                 mHandler.sendMessage(mHandler.obtainMessage(EVENT_WIRED_HEADSET_PLUG, 0));
1469             } else if (action.equals(Intent.ACTION_BATTERY_LOW)) {
1470                 if (VDBG) Log.d(LOG_TAG, "mReceiver: ACTION_BATTERY_LOW");
1471                 notifier.sendBatteryLow();  // Play a warning tone if in-call
1472             } else if ((action.equals(TelephonyIntents.ACTION_SIM_STATE_CHANGED)) &&
1473                     (mPUKEntryActivity != null)) {
1474                 // if an attempt to un-PUK-lock the device was made, while we're
1475                 // receiving this state change notification, notify the handler.
1476                 // NOTE: This is ONLY triggered if an attempt to un-PUK-lock has
1477                 // been attempted.
1478                 mHandler.sendMessage(mHandler.obtainMessage(EVENT_SIM_STATE_CHANGED,
1479                         intent.getStringExtra(IccCard.INTENT_KEY_ICC_STATE)));
1480             } else if (action.equals(TelephonyIntents.ACTION_RADIO_TECHNOLOGY_CHANGED)) {
1481                 String newPhone = intent.getStringExtra(Phone.PHONE_NAME_KEY);
1482                 Log.d(LOG_TAG, "Radio technology switched. Now " + newPhone + " is active.");
1483                 initForNewRadioTechnology();
1484             } else if (action.equals(TelephonyIntents.ACTION_SERVICE_STATE_CHANGED)) {
1485                 handleServiceStateChanged(intent);
1486             } else if (action.equals(TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED)) {
1487                 if (TelephonyCapabilities.supportsEcm(phone)) {
1488                     Log.d(LOG_TAG, "Emergency Callback Mode arrived in PhoneApp.");
1489                     // Start Emergency Callback Mode service
1490                     if (intent.getBooleanExtra("phoneinECMState", false)) {
1491                         context.startService(new Intent(context,
1492                                 EmergencyCallbackModeService.class));
1493                     }
1494                 } else {
1495                     // It doesn't make sense to get ACTION_EMERGENCY_CALLBACK_MODE_CHANGED
1496                     // on a device that doesn't support ECM in the first place.
1497                     Log.e(LOG_TAG, "Got ACTION_EMERGENCY_CALLBACK_MODE_CHANGED, "
1498                           + "but ECM isn't supported for phone: " + phone.getPhoneName());
1499                 }
1500             } else if (action.equals(Intent.ACTION_DOCK_EVENT)) {
1501                 mDockState = intent.getIntExtra(Intent.EXTRA_DOCK_STATE,
1502                         Intent.EXTRA_DOCK_STATE_UNDOCKED);
1503                 if (VDBG) Log.d(LOG_TAG, "ACTION_DOCK_EVENT -> mDockState = " + mDockState);
1504                 mHandler.sendMessage(mHandler.obtainMessage(EVENT_DOCK_STATE_CHANGED, 0));
1505             } else if (action.equals(TtyIntent.TTY_PREFERRED_MODE_CHANGE_ACTION)) {
1506                 mPreferredTtyMode = intent.getIntExtra(TtyIntent.TTY_PREFFERED_MODE,
1507                                                        Phone.TTY_MODE_OFF);
1508                 if (VDBG) Log.d(LOG_TAG, "mReceiver: TTY_PREFERRED_MODE_CHANGE_ACTION");
1509                 if (VDBG) Log.d(LOG_TAG, "    mode: " + mPreferredTtyMode);
1510                 mHandler.sendMessage(mHandler.obtainMessage(EVENT_TTY_PREFERRED_MODE_CHANGED, 0));
1511             } else if (action.equals(AudioManager.RINGER_MODE_CHANGED_ACTION)) {
1512                 int ringerMode = intent.getIntExtra(AudioManager.EXTRA_RINGER_MODE,
1513                         AudioManager.RINGER_MODE_NORMAL);
1514                 if (ringerMode == AudioManager.RINGER_MODE_SILENT) {
1515                     notifier.silenceRinger();
1516                 }
1517             }
1518         }
1519     }
1520 
1521     /**
1522      * Broadcast receiver for the ACTION_MEDIA_BUTTON broadcast intent.
1523      *
1524      * This functionality isn't lumped in with the other intents in
1525      * PhoneAppBroadcastReceiver because we instantiate this as a totally
1526      * separate BroadcastReceiver instance, since we need to manually
1527      * adjust its IntentFilter's priority (to make sure we get these
1528      * intents *before* the media player.)
1529      */
1530     private class MediaButtonBroadcastReceiver extends BroadcastReceiver {
1531         @Override
onReceive(Context context, Intent intent)1532         public void onReceive(Context context, Intent intent) {
1533             KeyEvent event = (KeyEvent) intent.getParcelableExtra(Intent.EXTRA_KEY_EVENT);
1534             if (VDBG) Log.d(LOG_TAG,
1535                            "MediaButtonBroadcastReceiver.onReceive()...  event = " + event);
1536             if ((event != null)
1537                 && (event.getKeyCode() == KeyEvent.KEYCODE_HEADSETHOOK)) {
1538                 if (VDBG) Log.d(LOG_TAG, "MediaButtonBroadcastReceiver: HEADSETHOOK");
1539                 boolean consumed = PhoneUtils.handleHeadsetHook(phone, event);
1540                 if (VDBG) Log.d(LOG_TAG, "==> handleHeadsetHook(): consumed = " + consumed);
1541                 if (consumed) {
1542                     // If a headset is attached and the press is consumed, also update
1543                     // any UI items (such as an InCallScreen mute button) that may need to
1544                     // be updated if their state changed.
1545                     updateInCallScreen();  // Has no effect if the InCallScreen isn't visible
1546                     abortBroadcast();
1547                 }
1548             } else {
1549                 if (mCM.getState() != Phone.State.IDLE) {
1550                     // If the phone is anything other than completely idle,
1551                     // then we consume and ignore any media key events,
1552                     // Otherwise it is too easy to accidentally start
1553                     // playing music while a phone call is in progress.
1554                     if (VDBG) Log.d(LOG_TAG, "MediaButtonBroadcastReceiver: consumed");
1555                     abortBroadcast();
1556                 }
1557             }
1558         }
1559     }
1560 
handleServiceStateChanged(Intent intent)1561     private void handleServiceStateChanged(Intent intent) {
1562         /**
1563          * This used to handle updating EriTextWidgetProvider this routine
1564          * and and listening for ACTION_SERVICE_STATE_CHANGED intents could
1565          * be removed. But leaving just in case it might be needed in the near
1566          * future.
1567          */
1568 
1569         // If service just returned, start sending out the queued messages
1570         ServiceState ss = ServiceState.newFromBundle(intent.getExtras());
1571 
1572         if (ss != null) {
1573             int state = ss.getState();
1574             notificationMgr.updateNetworkSelection(state);
1575         }
1576     }
1577 
isOtaCallInActiveState()1578     public boolean isOtaCallInActiveState() {
1579         boolean otaCallActive = false;
1580         if (mInCallScreen != null) {
1581             otaCallActive = mInCallScreen.isOtaCallInActiveState();
1582         }
1583         if (VDBG) Log.d(LOG_TAG, "- isOtaCallInActiveState " + otaCallActive);
1584         return otaCallActive;
1585     }
1586 
isOtaCallInEndState()1587     public boolean isOtaCallInEndState() {
1588         boolean otaCallEnded = false;
1589         if (mInCallScreen != null) {
1590             otaCallEnded = mInCallScreen.isOtaCallInEndState();
1591         }
1592         if (VDBG) Log.d(LOG_TAG, "- isOtaCallInEndState " + otaCallEnded);
1593         return otaCallEnded;
1594     }
1595 
1596     // it is safe to call clearOtaState() even if the InCallScreen isn't active
clearOtaState()1597     public void clearOtaState() {
1598         if (DBG) Log.d(LOG_TAG, "- clearOtaState ...");
1599         if ((mInCallScreen != null)
1600                 && (otaUtils != null)) {
1601             otaUtils.cleanOtaScreen(true);
1602             if (DBG) Log.d(LOG_TAG, "  - clearOtaState clears OTA screen");
1603         }
1604     }
1605 
1606     // it is safe to call dismissOtaDialogs() even if the InCallScreen isn't active
dismissOtaDialogs()1607     public void dismissOtaDialogs() {
1608         if (DBG) Log.d(LOG_TAG, "- dismissOtaDialogs ...");
1609         if ((mInCallScreen != null)
1610                 && (otaUtils != null)) {
1611             otaUtils.dismissAllOtaDialogs();
1612             if (DBG) Log.d(LOG_TAG, "  - dismissOtaDialogs clears OTA dialogs");
1613         }
1614     }
1615 
1616     // it is safe to call clearInCallScreenMode() even if the InCallScreen isn't active
clearInCallScreenMode()1617     public void clearInCallScreenMode() {
1618         if (DBG) Log.d(LOG_TAG, "- clearInCallScreenMode ...");
1619         if (mInCallScreen != null) {
1620             mInCallScreen.resetInCallScreenMode();
1621         }
1622     }
1623 
1624     /**
1625      * Force the in-call UI to refresh itself, if it's currently visible.
1626      *
1627      * This method can be used any time there's a state change anywhere in
1628      * the phone app that needs to be reflected in the onscreen UI.
1629      *
1630      * Note that it's *not* necessary to manually refresh the in-call UI
1631      * (via this method) for regular telephony state changes like
1632      * DIALING -> ALERTING -> ACTIVE, since the InCallScreen already
1633      * listens for those state changes itself.
1634      *
1635      * This method does *not* force the in-call UI to come up if it's not
1636      * already visible.  To do that, use displayCallScreen().
1637      */
updateInCallScreen()1638     /* package */ void updateInCallScreen() {
1639         if (DBG) Log.d(LOG_TAG, "- updateInCallScreen()...");
1640         if (mInCallScreen != null) {
1641             // Post an updateScreen() request.  Note that the
1642             // updateScreen() call will end up being a no-op if the
1643             // InCallScreen isn't the foreground activity.
1644             mInCallScreen.requestUpdateScreen();
1645         }
1646     }
1647 
handleQueryTTYModeResponse(Message msg)1648     private void handleQueryTTYModeResponse(Message msg) {
1649         AsyncResult ar = (AsyncResult) msg.obj;
1650         if (ar.exception != null) {
1651             if (DBG) Log.d(LOG_TAG, "handleQueryTTYModeResponse: Error getting TTY state.");
1652         } else {
1653             if (DBG) Log.d(LOG_TAG,
1654                            "handleQueryTTYModeResponse: TTY enable state successfully queried.");
1655 
1656             int ttymode = ((int[]) ar.result)[0];
1657             if (DBG) Log.d(LOG_TAG, "handleQueryTTYModeResponse:ttymode=" + ttymode);
1658 
1659             Intent ttyModeChanged = new Intent(TtyIntent.TTY_ENABLED_CHANGE_ACTION);
1660             ttyModeChanged.putExtra("ttyEnabled", ttymode != Phone.TTY_MODE_OFF);
1661             sendBroadcast(ttyModeChanged);
1662 
1663             String audioTtyMode;
1664             switch (ttymode) {
1665             case Phone.TTY_MODE_FULL:
1666                 audioTtyMode = "tty_full";
1667                 break;
1668             case Phone.TTY_MODE_VCO:
1669                 audioTtyMode = "tty_vco";
1670                 break;
1671             case Phone.TTY_MODE_HCO:
1672                 audioTtyMode = "tty_hco";
1673                 break;
1674             case Phone.TTY_MODE_OFF:
1675             default:
1676                 audioTtyMode = "tty_off";
1677                 break;
1678             }
1679             AudioManager audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
1680             audioManager.setParameters("tty_mode="+audioTtyMode);
1681         }
1682     }
1683 
handleSetTTYModeResponse(Message msg)1684     private void handleSetTTYModeResponse(Message msg) {
1685         AsyncResult ar = (AsyncResult) msg.obj;
1686 
1687         if (ar.exception != null) {
1688             if (DBG) Log.d (LOG_TAG,
1689                     "handleSetTTYModeResponse: Error setting TTY mode, ar.exception"
1690                     + ar.exception);
1691         }
1692         phone.queryTTYMode(mHandler.obtainMessage(EVENT_TTY_MODE_GET));
1693     }
1694 
clearUserActivityTimeout()1695     /* package */ void clearUserActivityTimeout() {
1696         try {
1697             mPowerManagerService.clearUserActivityTimeout(SystemClock.uptimeMillis(),
1698                     10*1000 /* 10 sec */);
1699         } catch (RemoteException ex) {
1700             // System process is dead.
1701         }
1702     }
1703 
1704     /**
1705      * "Call origin" may be used by Contacts app to specify where the phone call comes from.
1706      * Currently, the only permitted value for this extra is {@link #ALLOWED_EXTRA_CALL_ORIGIN}.
1707      * Any other value will be ignored, to make sure that malicious apps can't trick the in-call
1708      * UI into launching some random other app after a call ends.
1709      *
1710      * TODO: make this more generic. Note that we should let the "origin" specify its package
1711      * while we are now assuming it is "com.android.contacts"
1712      */
1713     public static final String EXTRA_CALL_ORIGIN = "com.android.phone.CALL_ORIGIN";
1714     private static final String DEFAULT_CALL_ORIGIN_PACKAGE = "com.android.contacts";
1715     private static final String ALLOWED_EXTRA_CALL_ORIGIN =
1716             "com.android.contacts.activities.DialtactsActivity";
1717 
setLatestActiveCallOrigin(String callOrigin)1718     public void setLatestActiveCallOrigin(String callOrigin) {
1719         inCallUiState.latestActiveCallOrigin = callOrigin;
1720     }
1721 
1722     /**
1723      * @return Intent which will be used when in-call UI is shown and the phone call is hang up.
1724      * By default CallLog screen will be introduced, but the destination may change depending on
1725      * its latest call origin state.
1726      */
createPhoneEndIntentUsingCallOrigin()1727     public Intent createPhoneEndIntentUsingCallOrigin() {
1728         if (TextUtils.equals(inCallUiState.latestActiveCallOrigin, ALLOWED_EXTRA_CALL_ORIGIN)) {
1729             if (VDBG) Log.d(LOG_TAG, "Valid latestActiveCallOrigin("
1730                     + inCallUiState.latestActiveCallOrigin + ") was found. "
1731                     + "Go back to the previous screen.");
1732             // Right now we just launch the Activity which launched in-call UI. Note that we're
1733             // assuming the origin is from "com.android.contacts", which may be incorrect in the
1734             // future.
1735             final Intent intent = new Intent();
1736             intent.setClassName(DEFAULT_CALL_ORIGIN_PACKAGE, inCallUiState.latestActiveCallOrigin);
1737             return intent;
1738         } else {
1739             if (VDBG) Log.d(LOG_TAG, "Current latestActiveCallOrigin ("
1740                     + inCallUiState.latestActiveCallOrigin + ") is not valid. "
1741                     + "Just use CallLog as a default destination.");
1742             return PhoneApp.createCallLogIntent();
1743         }
1744     }
1745 }
1746