am 448c256d: (-s ours) am 6c91d20e: Fix exported property on NotificationBroadcastReceiver.

* commit '448c256d6c9b86599c7c21e7fb61929704eeed5e':
  Fix exported property on NotificationBroadcastReceiver.
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index aabff7b..e9173e5 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -15,6 +15,7 @@
 -->
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
         package="com.android.phone"
         coreApp="true"
         android:sharedUserId="android.uid.phone"
@@ -82,7 +83,9 @@
     <uses-permission android:name="android.permission.USE_SIP" />
     <uses-permission android:name="android.permission.REBOOT" />
     <uses-permission android:name="android.permission.UPDATE_LOCK" />
+    <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" />
     <uses-permission android:name="com.android.smspush.WAPPUSH_MANAGER_BIND" />
+    <uses-permission android:name="android.permission.MANAGE_USERS" />
 
     <!-- This tells the activity manager to not delay any of our activity
          start requests, even if they happen immediately after the user
@@ -92,10 +95,11 @@
     <application android:name="PhoneApp"
                  android:persistent="true"
                  android:label="@string/phoneAppLabel"
-                 android:icon="@drawable/ic_launcher_phone">
+                 android:icon="@mipmap/ic_launcher_phone">
             <provider android:name="IccProvider"
                       android:authorities="icc"
                       android:multiprocess="true"
+                      android:exported="true"
                       android:readPermission="android.permission.READ_CONTACTS"
                       android:writePermission="android.permission.WRITE_CONTACTS" />
 
@@ -141,7 +145,7 @@
         <activity android:name="OutgoingCallBroadcaster"
                 android:theme="@style/OutgoingCallBroadcasterTheme"
                 android:permission="android.permission.CALL_PHONE"
-                android:screenOrientation="portrait"
+                android:screenOrientation="nosensor"
                 android:configChanges="orientation|screenSize|keyboardHidden">
             <!-- CALL action intent filters, for the various ways
                  of initiating an outgoing call. -->
@@ -198,6 +202,7 @@
 
         <activity-alias android:name="PrivilegedOutgoingCallBroadcaster"
                 android:targetActivity="OutgoingCallBroadcaster"
+                android:screenOrientation="nosensor"
                 android:permission="android.permission.CALL_PRIVILEGED">
             <intent-filter android:priority="1000">
                 <action android:name="android.intent.action.CALL_PRIVILEGED" />
@@ -241,8 +246,8 @@
             android:label="@string/phoneIconLabel"
             android:excludeFromRecents="true"
             android:launchMode="singleInstance"
-            android:screenOrientation="portrait"
-            android:configChanges="orientation|screenSize|keyboardHidden|uiMode"
+            android:screenOrientation="nosensor"
+            android:configChanges="keyboardHidden"
             android:exported="false">
         </activity>
 
@@ -435,15 +440,16 @@
             </intent-filter>
         </activity>
 
-        <!-- bluetooth headset service -->
-        <service android:name="BluetoothHeadsetService">
+        <!-- bluetooth phone service -->
+        <service android:name="BluetoothPhoneService">
             <intent-filter>
-                <action android:name="android.bluetooth.IBluetoothHeadset" />
+                <action android:name="android.bluetooth.IBluetoothHeadsetPhone" />
             </intent-filter>
         </service>
 
         <!-- Broadcast Receiver that will process BOOT Complete and launch OTA -->
-        <receiver android:name="OtaStartupReceiver" android:exported="false">
+        <receiver android:name="OtaStartupReceiver" android:exported="false"
+                androidprv:primaryUserOnly="true">
             <intent-filter android:priority="100">
                  <action android:name="android.intent.action.BOOT_COMPLETED"/>
             </intent-filter>
@@ -495,7 +501,7 @@
         </activity>
         <activity android:name=".SipCallOptionHandler"
                 android:theme="@style/SipCallOptionHandlerTheme"
-                android:screenOrientation="portrait"
+                android:screenOrientation="nosensor"
                 android:configChanges="orientation|screenSize|keyboardHidden">
         </activity>
 
@@ -515,7 +521,7 @@
         </receiver>
 
         <!-- BroadcastReceiver for receiving Intents from Notification mechanism. -->
-        <receiver android:name="PhoneApp$NotificationBroadcastReceiver" android:exported="false">
+        <receiver android:name="PhoneGlobals$NotificationBroadcastReceiver" android:exported="false">
             <intent-filter>
                 <action android:name="com.android.phone.ACTION_HANG_UP_ONGOING_CALL" />
                 <action android:name="com.android.phone.ACTION_CALL_BACK_FROM_NOTIFICATION" />
diff --git a/res/drawable-hdpi/ic_launcher_phone.png b/res/drawable-hdpi/ic_launcher_phone.png
deleted file mode 100644
index 5a3dff1..0000000
--- a/res/drawable-hdpi/ic_launcher_phone.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-mdpi/ic_launcher_phone.png b/res/drawable-mdpi/ic_launcher_phone.png
deleted file mode 100644
index 9ea0d8c..0000000
--- a/res/drawable-mdpi/ic_launcher_phone.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-nodpi/background_dial_holo_dark.png b/res/drawable-nodpi/background_dial_holo_dark.png
new file mode 100644
index 0000000..3dba50c
--- /dev/null
+++ b/res/drawable-nodpi/background_dial_holo_dark.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_launcher_phone.png b/res/drawable-xhdpi/ic_launcher_phone.png
deleted file mode 100644
index e97836c..0000000
--- a/res/drawable-xhdpi/ic_launcher_phone.png
+++ /dev/null
Binary files differ
diff --git a/res/layout-land/incall_screen.xml b/res/layout-land/incall_screen.xml
new file mode 100644
index 0000000..1278115
--- /dev/null
+++ b/res/layout-land/incall_screen.xml
@@ -0,0 +1,80 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2012 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<!-- In-call Phone UI; see InCallScreen.java. -->
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/landscape_incall_screen"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+    <!-- The "Call Card", which displays info about the currently
+         active phone call(s) on the device.  See call_card.xml. -->
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:background="@drawable/background_dial_holo_dark">
+        <include
+            layout="@layout/call_card"
+            android:id="@+id/callCard"
+            android:layout_width="0dp"
+            android:layout_weight="3"
+            android:layout_height="match_parent" />
+        <!-- Note: This center margin is repeated in layout-land/incall_touch_ui
+             Both layouts need to have this margin to be aligned correctly. -->
+        <View
+            android:layout_width="@dimen/dialpad_center_margin"
+            android:layout_weight="0"
+            android:layout_height="match_parent" />
+        <View
+            android:layout_width="0dp"
+            android:layout_weight="2"
+            android:layout_height="match_parent" />
+    </LinearLayout>
+
+    <!-- In-call onscreen touch controls; see InCallTouchUi.java.
+         This widget contains the cluster of buttons shown at the right
+         of the in-call screen, and also the DTMF dialpad (which, when
+         visible, covers the contact picture/call_card on the left half of the screen) -->
+
+    <ViewStub
+        android:id="@+id/inCallTouchUiStub"
+        android:layout="@layout/incall_touch_ui"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent" />
+    <ViewStub
+        android:id="@+id/inCallTouchUiCdmaStub"
+        android:layout="@layout/incall_touch_ui_cdma"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent" />
+
+    <!-- ViewStub for OTASP-related UI elements (for the CDMA "activation"
+         call.)  Note that this ViewStub provides the *entire* OTASP
+         screen, including the status area at the top *and* touch controls
+         at the bottom of the screen.  The regular CallCard and the
+         InCallTouchUi widget are not used at all during an OTASP call. -->
+    <ViewStub android:id="@+id/otaCallCardStub"
+              android:layout="@layout/otacall_card"
+              android:layout_width="match_parent"
+              android:layout_height="match_parent" />
+
+    <!-- The "Manage conference" UI.  This panel is displayed (and covers up
+         the entire normal in-call UI) when the user clicks "Manage conference"
+         during a GSM conference call. -->
+    <ViewStub android:id="@+id/manageConferencePanelStub"
+              android:layout="@layout/manage_conference_panel"
+              android:layout_width="match_parent"
+              android:layout_height="match_parent" />
+
+</FrameLayout>
diff --git a/res/layout-land/incall_touch_ui.xml b/res/layout-land/incall_touch_ui.xml
new file mode 100644
index 0000000..7ab56a1
--- /dev/null
+++ b/res/layout-land/incall_touch_ui.xml
@@ -0,0 +1,251 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2012 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<!-- In-call onscreen touch UI elements, used on some platforms.
+
+     This layout is a fullscreen overlay, drawn on top of the
+     non-touch-sensitive parts of the in-call UI (i.e. the call card).
+
+     The top-level View here is a InCallTouchUi (FrameLayout) with 2 children:
+       (1) inCallControls: the widgets visible while a regular call (or calls) is in progress
+       (2) incomingCallWidget: the UI displayed while an incoming call is ringing
+     In usual cases, one of these is visible at any given moment.
+     One exception is when incomingCallWidget is fading-out. At that moment, we show
+     inCallControls beneath incomingCallWidget for smoother transition.
+     -->
+<com.android.phone.InCallTouchUi xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:prvandroid="http://schemas.android.com/apk/prv/res/android"
+    android:id="@+id/inCallTouchUi"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+
+    <!--
+        (1) inCallControls: the widgets visible while a regular call
+        (or calls) is in progress
+    -->
+    <LinearLayout
+        android:id="@+id/inCallControls"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:visibility="gone">
+
+        <!-- DTMF dialpad shown in the left part of the screen.
+             This is wrapped in a FrameLayout because otherwise the ViewStub has no width,
+             causing the other buttons to span the full width of the screen -->
+        <FrameLayout
+            android:layout_width="0dp"
+            android:layout_weight="3"
+            android:layout_height="match_parent">
+            <ViewStub
+                android:id="@+id/dtmf_twelve_key_dialer_stub"
+                android:layout="@layout/dtmf_twelve_key_dialer_view"
+                android:layout_width="match_parent"
+                android:layout_height="match_parent" />
+
+            <!-- The "extra button row": Rare button used for statues such as conference
+                 calls (GSM). Refer to layout(portrait)/incall_touch_ui for more details.
+                 When shown, this extra button row hovers over the call card, just above
+                 the primary_call_banner of layout-land/primary_call_info. -->
+            <ViewStub
+                android:id="@+id/extraButtonRow"
+                android:layout_gravity="bottom"
+                android:layout_marginBottom="@dimen/call_banner_height"
+                android:layout="@layout/extra_button_row"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content" />
+        </FrameLayout>
+
+        <!-- Note: This center margin is repeated in layout-land/incall_screen -->
+        <View
+            android:layout_width="@dimen/dialpad_center_margin"
+            android:layout_height="match_parent"
+            android:background="#66000000" />
+
+        <!-- Cluster of buttons on the right part of the screen.
+             It is named id/bottomButtons from the naming when in portrait layout. -->
+        <LinearLayout
+            android:id="@+id/bottomButtons"
+            android:background="@drawable/dialpad_background"
+            android:orientation="vertical"
+            android:layout_width="0dp"
+            android:layout_weight="2"
+            android:layout_height="match_parent">
+
+            <!-- "Audio mode" -->
+            <!-- This is a multi-mode button that can behave either like a
+                 simple "compound button" with two states *or* like an
+                 action button that brings up a popup menu; see
+                 btn_compound_audio.xml and InCallTouchUi.updateAudioButton()
+                 for the full details. -->
+            <ToggleButton
+                android:id="@+id/audioButton"
+                android:layout_height="0dp"
+                android:layout_weight="1"
+                android:layout_width="match_parent"
+                style="@style/InCallCompoundButton"
+                android:background="@drawable/btn_compound_audio"
+                android:contentDescription="@string/onscreenAudioText" />
+
+            <View
+                android:layout_height="@dimen/dialpad_button_margin"
+                android:layout_width="match_parent"
+                android:background="#66000000" />
+
+            <LinearLayout
+                android:layout_height="0dp"
+                android:layout_weight="1"
+                android:layout_width="match_parent">
+                <ToggleButton
+                    android:id="@+id/muteButton"
+                    android:layout_width="0dp"
+                    android:layout_weight="1"
+                    android:layout_height="match_parent"
+                    style="@style/InCallCompoundButton"
+                    android:background="@drawable/btn_compound_mute"
+                    android:contentDescription="@string/onscreenMuteText" />
+                <View
+                    android:layout_width="@dimen/dialpad_button_margin"
+                    android:layout_height="match_parent"
+                    android:background="#66000000" />
+                <!-- This slot is either "Hold" or "Swap", depending on
+                     the state of the call.   One or the other of these
+                     must always be set to GONE. -->
+                <!-- "Hold" -->
+                <!-- This is a "compound button": it has checked and unchecked states. -->
+                <ToggleButton
+                    android:id="@+id/holdButton"
+                    android:layout_width="0dp"
+                    android:layout_weight="1"
+                    android:layout_height="match_parent"
+                    style="@style/InCallCompoundButton"
+                    android:background="@drawable/btn_compound_hold"
+                    android:contentDescription="@string/onscreenHoldText" />
+                <!-- "Swap" (or "Manage calls" in some CDMA states) -->
+                <ImageButton
+                    android:id="@+id/swapButton"
+                    android:layout_width="0dp"
+                    android:layout_weight="1"
+                    android:layout_height="match_parent"
+                    style="@style/InCallButton"
+                    android:src="@drawable/ic_incall_switch_holo_dark"
+                    android:contentDescription="@string/onscreenSwapCallsText" />
+            </LinearLayout>
+
+            <View
+                android:layout_height="@dimen/dialpad_button_margin"
+                android:layout_width="match_parent"
+                android:background="#66000000" />
+
+            <LinearLayout
+                android:layout_height="0dp"
+                android:layout_weight="1"
+                android:layout_width="match_parent">
+                <ToggleButton
+                    android:id="@+id/dialpadButton"
+                    android:layout_width="0dp"
+                    android:layout_weight="1"
+                    android:layout_height="match_parent"
+                    style="@style/InCallCompoundButton"
+                    android:background="@drawable/btn_compound_dialpad"
+                    android:contentDescription="@string/onscreenShowDialpadText" />
+                <View
+                    android:layout_width="@dimen/dialpad_button_margin"
+                    android:layout_height="match_parent"
+                    android:background="#66000000" />
+                <!-- This slot is either "Add" or "Merge", depending on
+                     the state of the call.  One or the other of these
+                     must always be set to GONE. -->
+                <!-- "Add Call" -->
+                <ImageButton
+                    android:id="@+id/addButton"
+                    android:layout_width="0dp"
+                    android:layout_weight="1"
+                    android:layout_height="match_parent"
+                    style="@style/InCallButton"
+                    android:src="@drawable/ic_add_contact_holo_dark"
+                    android:contentDescription="@string/onscreenAddCallText" />
+                <!-- "Merge calls" -->
+                <!-- This button is used only on GSM devices, where we know
+                     that "Add" and "Merge" are never available at the same time.
+                     The "Merge" button for CDMA devices is "cdmaMergeButton" above. -->
+                <ImageButton
+                    android:id="@+id/mergeButton"
+                    android:layout_width="0dp"
+                    android:layout_weight="1"
+                    android:layout_height="match_parent"
+                    style="@style/InCallButton"
+                    android:src="@drawable/ic_merge_holo_dark"
+                    android:contentDescription="@string/onscreenMergeCallsText" />
+            </LinearLayout>
+
+            <!-- This spacer is not used in GSM, so it has 0 width and height. The CDMA
+                 incall_touch_ui_cdma uses it as a spacer when a 5th button is shown. -->
+            <View
+                android:id="@+id/holdSwapSpacer"
+                android:layout_width="0dp"
+                android:layout_height="0dp" />
+            <View
+                android:layout_height="@dimen/dialpad_button_margin"
+                android:layout_width="match_parent"
+                android:background="#66000000" />
+            <ImageButton
+                android:id="@+id/endButton"
+                android:layout_height="@dimen/in_call_end_button_height"
+                android:layout_width="match_parent"
+                android:src="@drawable/ic_dial_end_call"
+                android:background="@drawable/end_call_background"
+                android:contentDescription="@string/onscreenEndCallText" />
+        </LinearLayout>
+    </LinearLayout>
+
+    <!--
+        (2) incomingCallWidget: the UI displayed while an incoming call is ringing.
+            See InCallTouchUi.showIncomingCallWidget().
+
+            Layout notes:
+            - Use an opaque black background since we need to cover up
+              a bit of the bottom of the contact photo
+            - The verticalOffset value gets us a little extra space above
+              the topmost "Respond by SMS" icon
+            - The negative layout_marginBottom shifts us slightly downward;
+              we're already aligned with the bottom of the screen, but we
+              don't have an icon in the downward direction so the whole
+              bottom area of this widget is just wasted space.
+    -->
+    <com.android.internal.widget.multiwaveview.GlowPadView
+        android:id="@+id/incomingCallWidget"
+        android:layout_width="wrap_content"
+        android:layout_height="match_parent"
+        android:layout_gravity="right"
+        android:background="@android:color/black"
+        android:visibility="gone"
+        android:gravity="top"
+
+        prvandroid:targetDrawables="@array/incoming_call_widget_3way_targets"
+        prvandroid:targetDescriptions="@array/incoming_call_widget_3way_target_descriptions"
+        prvandroid:directionDescriptions="@array/incoming_call_widget_3way_direction_descriptions"
+        prvandroid:handleDrawable="@drawable/ic_in_call_touch_handle"
+        prvandroid:innerRadius="@*android:dimen/glowpadview_inner_radius"
+        prvandroid:outerRadius="@*android:dimen/glowpadview_target_placement_radius"
+        prvandroid:outerRingDrawable="@*android:drawable/ic_lockscreen_outerring"
+        prvandroid:snapMargin="@*android:dimen/glowpadview_snap_margin"
+        prvandroid:vibrationDuration="20"
+        prvandroid:feedbackCount="1"
+        prvandroid:glowRadius="@*android:dimen/glowpadview_glow_radius"
+        prvandroid:pointDrawable="@*android:drawable/ic_lockscreen_glowdot"
+        />
+
+</com.android.phone.InCallTouchUi>
diff --git a/res/layout-land/incall_touch_ui_cdma.xml b/res/layout-land/incall_touch_ui_cdma.xml
new file mode 100644
index 0000000..ce96612
--- /dev/null
+++ b/res/layout-land/incall_touch_ui_cdma.xml
@@ -0,0 +1,248 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2012 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<!-- In-call onscreen touch UI elements, used on some platforms.
+
+     This layout is a fullscreen overlay, drawn on top of the
+     non-touch-sensitive parts of the in-call UI (i.e. the call card).
+
+     The top-level View here is a InCallTouchUi (FrameLayout) with 2 children:
+       (1) inCallControls: the widgets visible while a regular call (or calls) is in progress
+       (2) incomingCallWidget: the UI displayed while an incoming call is ringing
+     In usual cases, one of these is visible at any given moment.
+     One exception is when incomingCallWidget is fading-out. At that moment, we show
+     inCallControls beneath incomingCallWidget for smoother transition.
+     -->
+<com.android.phone.InCallTouchUi xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:prvandroid="http://schemas.android.com/apk/prv/res/android"
+    android:id="@+id/inCallTouchUi"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+
+    <!--
+        (1) inCallControls: the widgets visible while a regular call
+        (or calls) is in progress
+    -->
+    <LinearLayout
+        android:id="@+id/inCallControls"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:visibility="gone">
+
+        <!-- DTMF dialpad shown in the left part of the screen.
+             This is wrapped in a FrameLayout because otherwise the ViewStub has no width,
+             causing the other buttons to span the full width of the screen -->
+        <FrameLayout
+            android:layout_width="0dp"
+            android:layout_weight="3"
+            android:layout_height="match_parent">
+            <ViewStub
+                android:id="@+id/dtmf_twelve_key_dialer_stub"
+                android:layout="@layout/dtmf_twelve_key_dialer_view"
+                android:layout_width="match_parent"
+                android:layout_height="match_parent" />
+
+            <!-- The "extra button row": Rare button used for statues such as conference
+                 calls (GSM). Refer to layout(portrait)/incall_touch_ui for more details.
+                 When shown, this extra button row hovers over the call card, just above
+                 the primary_call_banner of layout-land/primary_call_info.
+                 I believe, since this is the CDMA layout, that the button might not be shown. -->
+            <ViewStub
+                android:id="@+id/extraButtonRow"
+                android:layout_gravity="bottom"
+                android:layout_marginBottom="@dimen/call_banner_height"
+                android:layout="@layout/extra_button_row"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content" />
+        </FrameLayout>
+
+        <!-- Note: This center margin is repeated in layout-land/incall_screen -->
+        <View
+            android:layout_width="@dimen/dialpad_center_margin"
+            android:layout_height="match_parent"
+            android:background="#66000000" />
+
+        <!-- Cluster of buttons on the right part of the screen.
+             It is named id/bottomButtons from the naming when in portrait layout. -->
+        <LinearLayout
+            android:id="@+id/bottomButtons"
+            android:background="@drawable/dialpad_background"
+            android:orientation="vertical"
+            android:layout_width="0dp"
+            android:layout_weight="2"
+            android:layout_height="match_parent">
+
+            <!-- This slot is either "Hold" or "Swap", depending on
+                 the state of the call.   One or the other of these
+                 must always be set to GONE. -->
+            <!-- "Hold" -->
+            <!-- This is a "compound button": it has checked and unchecked states. -->
+            <ToggleButton
+                android:id="@+id/holdButton"
+                android:layout_height="0dp"
+                android:layout_weight="1"
+                android:layout_width="match_parent"
+                style="@style/InCallCompoundButton"
+                android:background="@drawable/btn_compound_hold"
+                android:contentDescription="@string/onscreenHoldText" />
+            <!-- "Swap" (or "Manage calls" in some CDMA states) -->
+            <ImageButton
+                android:id="@+id/swapButton"
+                android:layout_height="0dp"
+                android:layout_weight="1"
+                android:layout_width="match_parent"
+                style="@style/InCallButton"
+                android:src="@drawable/ic_incall_switch_holo_dark"
+                android:contentDescription="@string/onscreenSwapCallsText" />
+
+
+            <View
+                android:id="@+id/holdSwapSpacer"
+                android:layout_height="@dimen/dialpad_button_margin"
+                android:layout_width="match_parent"
+                android:background="#66000000" />
+
+            <LinearLayout
+                android:layout_height="0dp"
+                android:layout_weight="1"
+                android:layout_width="match_parent">
+                <ToggleButton
+                    android:id="@+id/muteButton"
+                    android:layout_width="0dp"
+                    android:layout_weight="1"
+                    android:layout_height="match_parent"
+                    style="@style/InCallCompoundButton"
+                    android:background="@drawable/btn_compound_mute"
+                    android:contentDescription="@string/onscreenMuteText" />
+                <View
+                    android:layout_width="@dimen/dialpad_button_margin"
+                    android:layout_height="match_parent"
+                    android:background="#66000000" />
+                <!-- "Audio mode" -->
+                <!-- This is a multi-mode button that can behave either like a
+                     simple "compound button" with two states *or* like an
+                     action button that brings up a popup menu; see
+                     btn_compound_audio.xml and InCallTouchUi.updateAudioButton()
+                     for the full details. -->
+                <ToggleButton
+                    android:id="@+id/audioButton"
+                    android:layout_width="0dp"
+                    android:layout_weight="1"
+                    android:layout_height="match_parent"
+                    style="@style/InCallCompoundButton"
+                    android:background="@drawable/btn_compound_audio"
+                    android:contentDescription="@string/onscreenAudioText" />
+            </LinearLayout>
+
+            <View
+                android:layout_height="@dimen/dialpad_button_margin"
+                android:layout_width="match_parent"
+                android:background="#66000000" />
+
+            <LinearLayout
+                android:layout_height="0dp"
+                android:layout_weight="1"
+                android:layout_width="match_parent">
+                <ToggleButton
+                    android:id="@+id/dialpadButton"
+                    android:layout_width="0dp"
+                    android:layout_weight="1"
+                    android:layout_height="match_parent"
+                    style="@style/InCallCompoundButton"
+                    android:background="@drawable/btn_compound_dialpad"
+                    android:contentDescription="@string/onscreenShowDialpadText" />
+                <View
+                    android:layout_width="@dimen/dialpad_button_margin"
+                    android:layout_height="match_parent"
+                    android:background="#66000000" />
+                <!-- This slot is either "Add" or "Merge", depending on
+                     the state of the call.  One or the other of these
+                     must always be set to GONE. -->
+                <!-- "Add Call" -->
+                <ImageButton
+                    android:id="@+id/addButton"
+                    android:layout_width="0dp"
+                    android:layout_weight="1"
+                    android:layout_height="match_parent"
+                    style="@style/InCallButton"
+                    android:src="@drawable/ic_add_contact_holo_dark"
+                    android:contentDescription="@string/onscreenAddCallText" />
+                <!-- "Merge calls" -->
+                <!-- This button is used only on GSM devices, where we know
+                     that "Add" and "Merge" are never available at the same time.
+                     The "Merge" button for CDMA devices is "cdmaMergeButton" above. -->
+                <ImageButton
+                    android:id="@+id/mergeButton"
+                    android:layout_width="0dp"
+                    android:layout_weight="1"
+                    android:layout_height="match_parent"
+                    style="@style/InCallButton"
+                    android:src="@drawable/ic_merge_holo_dark"
+                    android:contentDescription="@string/onscreenMergeCallsText" />
+            </LinearLayout>
+
+            <View
+                android:layout_height="@dimen/dialpad_button_margin"
+                android:layout_width="match_parent"
+                android:background="#66000000" />
+            <ImageButton
+                android:id="@+id/endButton"
+                android:layout_height="@dimen/in_call_end_button_height"
+                android:layout_width="match_parent"
+                android:src="@drawable/ic_dial_end_call"
+                android:background="@drawable/end_call_background"
+                android:contentDescription="@string/onscreenEndCallText" />
+        </LinearLayout>
+    </LinearLayout>
+
+    <!--
+        (2) incomingCallWidget: the UI displayed while an incoming call is ringing.
+            See InCallTouchUi.showIncomingCallWidget().
+
+            Layout notes:
+            - Use an opaque black background since we need to cover up
+              a bit of the bottom of the contact photo
+            - The verticalOffset value gets us a little extra space above
+              the topmost "Respond by SMS" icon
+            - The negative layout_marginBottom shifts us slightly downward;
+              we're already aligned with the bottom of the screen, but we
+              don't have an icon in the downward direction so the whole
+              bottom area of this widget is just wasted space.
+    -->
+    <com.android.internal.widget.multiwaveview.GlowPadView
+        android:id="@+id/incomingCallWidget"
+        android:layout_width="wrap_content"
+        android:layout_height="match_parent"
+        android:layout_gravity="right"
+        android:background="@android:color/black"
+        android:visibility="gone"
+        android:gravity="top"
+
+        prvandroid:targetDrawables="@array/incoming_call_widget_3way_targets"
+        prvandroid:targetDescriptions="@array/incoming_call_widget_3way_target_descriptions"
+        prvandroid:directionDescriptions="@array/incoming_call_widget_3way_direction_descriptions"
+        prvandroid:handleDrawable="@drawable/ic_in_call_touch_handle"
+        prvandroid:innerRadius="@*android:dimen/glowpadview_inner_radius"
+        prvandroid:outerRadius="@*android:dimen/glowpadview_target_placement_radius"
+        prvandroid:outerRingDrawable="@*android:drawable/ic_lockscreen_outerring"
+        prvandroid:snapMargin="@*android:dimen/glowpadview_snap_margin"
+        prvandroid:vibrationDuration="20"
+        prvandroid:feedbackCount="1"
+        prvandroid:glowRadius="@*android:dimen/glowpadview_glow_radius"
+        prvandroid:pointDrawable="@*android:drawable/ic_lockscreen_glowdot"
+        />
+
+</com.android.phone.InCallTouchUi>
diff --git a/res/layout/incall_screen.xml b/res/layout/incall_screen.xml
index da9a509..64df29a 100644
--- a/res/layout/incall_screen.xml
+++ b/res/layout/incall_screen.xml
@@ -38,7 +38,6 @@
          of the in-call screen, and also the DTMF dialpad (which, when
          visible, covers the upper part of the screen too.) -->
     <include layout="@layout/incall_touch_ui"
-        android:id="@+id/inCallTouchUi"
         android:layout_width="match_parent"
         android:layout_height="match_parent"
         />
diff --git a/res/layout/incall_touch_ui.xml b/res/layout/incall_touch_ui.xml
index c070782..8dd8b61 100644
--- a/res/layout/incall_touch_ui.xml
+++ b/res/layout/incall_touch_ui.xml
@@ -28,6 +28,7 @@
      -->
 <com.android.phone.InCallTouchUi xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:prvandroid="http://schemas.android.com/apk/prv/res/android"
+    android:id="@+id/inCallTouchUi"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
     >
diff --git a/res/layout/manage_conference_panel.xml b/res/layout/manage_conference_panel.xml
index 7baf09b..f1fbfdf 100644
--- a/res/layout/manage_conference_panel.xml
+++ b/res/layout/manage_conference_panel.xml
@@ -19,6 +19,7 @@
      button while on a conference call. -->
 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
                 android:id="@+id/manageConferencePanel"
+                android:background="#FF000000"
                 android:layout_width="match_parent"
                 android:layout_height="match_parent"
                 android:visibility="gone"
diff --git a/res/layout/primary_call_info.xml b/res/layout/primary_call_info.xml
index 73718ee..099f19e 100644
--- a/res/layout/primary_call_info.xml
+++ b/res/layout/primary_call_info.xml
@@ -68,7 +68,7 @@
          and other status info.  This info is shown as a "banner"
          overlaid across the top of contact photo. -->
     <RelativeLayout android:id="@+id/primary_call_banner"
-        android:layout_alignParentTop="true"
+        style="@style/PrimaryCallInfoPrimaryCallBanner"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
         android:minHeight="@dimen/call_banner_height"
@@ -137,7 +137,7 @@
     </RelativeLayout>  <!-- End of call_banner -->
 
     <LinearLayout android:id="@+id/secondary_info_container"
-        android:layout_below="@id/primary_call_banner"
+        style="@style/PrimaryCallInfoSecondaryInfoContainer"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
         android:layout_gravity="center_vertical|right"
diff --git a/res/layout/secondary_call_info.xml b/res/layout/secondary_call_info.xml
index 0e6e65f..516b615 100644
--- a/res/layout/secondary_call_info.xml
+++ b/res/layout/secondary_call_info.xml
@@ -25,8 +25,6 @@
 
     <!-- Contact photo for call_info #2 -->
     <ImageView android:id="@+id/secondaryCallPhoto"
-        android:layout_alignParentLeft="true"
-        android:layout_alignParentTop="true"
         android:layout_width="match_parent"
         android:layout_height="match_parent"
         android:gravity="top|center_horizontal"
@@ -37,8 +35,6 @@
 
          TODO: We could do better. See equivalent in primary xml. -->
     <View android:id="@+id/dim_effect_for_secondary_photo"
-         android:layout_alignParentLeft="true"
-         android:layout_alignParentTop="true"
          android:layout_width="match_parent"
          android:layout_height="match_parent"
          android:background="@drawable/clickable_dim_effect"
@@ -46,6 +42,7 @@
 
     <!-- Name (or the phone number, if we don't have a name to display). -->
     <TextView android:id="@+id/secondaryCallName"
+        style="@style/SecondaryCallInfoSecondaryCallName"
         android:layout_width="match_parent"
         android:layout_height="@dimen/call_banner_height"
         android:gravity="top|left"
@@ -60,9 +57,9 @@
 
     <!-- Call status of the background call, usually the string "On hold". -->
     <TextView android:id="@+id/secondaryCallStatus"
+        style="@style/SecondaryCallInfoSecondaryCallStatus"
         android:layout_width="wrap_content"
         android:layout_height="@dimen/call_banner_height"
-        android:layout_gravity="top|right"
         android:gravity="top|right"
         android:paddingLeft="@dimen/call_banner_side_padding"
         android:paddingRight="@dimen/call_banner_side_padding"
diff --git a/res/mipmap-hdpi/ic_launcher_phone.png b/res/mipmap-hdpi/ic_launcher_phone.png
new file mode 100644
index 0000000..47d7894
--- /dev/null
+++ b/res/mipmap-hdpi/ic_launcher_phone.png
Binary files differ
diff --git a/res/mipmap-mdpi/ic_launcher_phone.png b/res/mipmap-mdpi/ic_launcher_phone.png
new file mode 100644
index 0000000..3b333cf
--- /dev/null
+++ b/res/mipmap-mdpi/ic_launcher_phone.png
Binary files differ
diff --git a/res/mipmap-xhdpi/ic_launcher_phone.png b/res/mipmap-xhdpi/ic_launcher_phone.png
new file mode 100644
index 0000000..020c2fa
--- /dev/null
+++ b/res/mipmap-xhdpi/ic_launcher_phone.png
Binary files differ
diff --git a/res/mipmap-xxhdpi/ic_launcher_contacts.png b/res/mipmap-xxhdpi/ic_launcher_contacts.png
new file mode 100644
index 0000000..99b403b
--- /dev/null
+++ b/res/mipmap-xxhdpi/ic_launcher_contacts.png
Binary files differ
diff --git a/res/mipmap-xxhdpi/ic_launcher_phone.png b/res/mipmap-xxhdpi/ic_launcher_phone.png
new file mode 100644
index 0000000..1594e4e
--- /dev/null
+++ b/res/mipmap-xxhdpi/ic_launcher_phone.png
Binary files differ
diff --git a/res/values-af/strings.xml b/res/values-af/strings.xml
index 0bfd714..ef82556 100644
--- a/res/values-af/strings.xml
+++ b/res/values-af/strings.xml
@@ -399,6 +399,7 @@
     <string name="card_title_hanging_up" msgid="3999101620995182450">"Lui af"</string>
     <string name="card_title_in_call" msgid="6346543933068225205">"In oproep"</string>
     <string name="card_title_my_phone_number" msgid="112428362494434191">"My nommer is <xliff:g id="MY_PHONE_NUMBER">%s</xliff:g>"</string>
+    <string name="notification_dialing" msgid="2107666444937350731">"Bel"</string>
     <string name="notification_missedCallTitle" msgid="7554385905572364535">"Gemiste oproep"</string>
     <string name="notification_missedCallsTitle" msgid="1361677948941502522">"Gemiste oproepe"</string>
     <string name="notification_missedCallsMsg" msgid="4575787816055205600">"<xliff:g id="NUM_MISSED_CALLS">%s</xliff:g> gemiste oproepe"</string>
diff --git a/res/values-am/strings.xml b/res/values-am/strings.xml
index a0da9d3..f068ba4 100644
--- a/res/values-am/strings.xml
+++ b/res/values-am/strings.xml
@@ -395,6 +395,7 @@
     <string name="card_title_hanging_up" msgid="3999101620995182450">"በመዝጋት ላይ"</string>
     <string name="card_title_in_call" msgid="6346543933068225205">"ጥሪ ላይ"</string>
     <string name="card_title_my_phone_number" msgid="112428362494434191">"ቁጥሬ<xliff:g id="MY_PHONE_NUMBER">%s</xliff:g> ነው"</string>
+    <string name="notification_dialing" msgid="2107666444937350731">"በመደወል ላይ"</string>
     <string name="notification_missedCallTitle" msgid="7554385905572364535">"ያመለጠጥሪ"</string>
     <string name="notification_missedCallsTitle" msgid="1361677948941502522">"ያመለጡ ጥሪዎች"</string>
     <string name="notification_missedCallsMsg" msgid="4575787816055205600">"<xliff:g id="NUM_MISSED_CALLS">%s</xliff:g> ያመለጡ ጥሪዎች"</string>
diff --git a/res/values-ar/strings.xml b/res/values-ar/strings.xml
index 0990b24..e04a955 100644
--- a/res/values-ar/strings.xml
+++ b/res/values-ar/strings.xml
@@ -395,6 +395,7 @@
     <string name="card_title_hanging_up" msgid="3999101620995182450">"إنهاء المكالمة"</string>
     <string name="card_title_in_call" msgid="6346543933068225205">"قيد الاتصال"</string>
     <string name="card_title_my_phone_number" msgid="112428362494434191">"رقمي هو <xliff:g id="MY_PHONE_NUMBER">%s</xliff:g>"</string>
+    <string name="notification_dialing" msgid="2107666444937350731">"جارٍ الطلب"</string>
     <string name="notification_missedCallTitle" msgid="7554385905572364535">"مكالمة فائتة"</string>
     <string name="notification_missedCallsTitle" msgid="1361677948941502522">"المكالمات الفائتة"</string>
     <string name="notification_missedCallsMsg" msgid="4575787816055205600">"<xliff:g id="NUM_MISSED_CALLS">%s</xliff:g> من المكالمات الفائتة"</string>
diff --git a/res/values-be/strings.xml b/res/values-be/strings.xml
index 5b1d820..9cf2c0a 100644
--- a/res/values-be/strings.xml
+++ b/res/values-be/strings.xml
@@ -395,6 +395,7 @@
     <string name="card_title_hanging_up" msgid="3999101620995182450">"Завяршэнне"</string>
     <string name="card_title_in_call" msgid="6346543933068225205">"У выкліку"</string>
     <string name="card_title_my_phone_number" msgid="112428362494434191">"Мой нумар – <xliff:g id="MY_PHONE_NUMBER">%s</xliff:g>"</string>
+    <string name="notification_dialing" msgid="2107666444937350731">"Набор"</string>
     <string name="notification_missedCallTitle" msgid="7554385905572364535">"Прапушчаны выклік"</string>
     <string name="notification_missedCallsTitle" msgid="1361677948941502522">"Прапушчаныя выклікі"</string>
     <string name="notification_missedCallsMsg" msgid="4575787816055205600">"Прапушчаных выклікаў: <xliff:g id="NUM_MISSED_CALLS">%s</xliff:g>"</string>
diff --git a/res/values-bg/strings.xml b/res/values-bg/strings.xml
index e859348..79f37ae 100644
--- a/res/values-bg/strings.xml
+++ b/res/values-bg/strings.xml
@@ -395,6 +395,7 @@
     <string name="card_title_hanging_up" msgid="3999101620995182450">"Приключване на разговора"</string>
     <string name="card_title_in_call" msgid="6346543933068225205">"Вх. обаждане"</string>
     <string name="card_title_my_phone_number" msgid="112428362494434191">"Моят номер е <xliff:g id="MY_PHONE_NUMBER">%s</xliff:g>"</string>
+    <string name="notification_dialing" msgid="2107666444937350731">"Набира се"</string>
     <string name="notification_missedCallTitle" msgid="7554385905572364535">"Пропуснато обаждане"</string>
     <string name="notification_missedCallsTitle" msgid="1361677948941502522">"Пропуснати обаждания"</string>
     <string name="notification_missedCallsMsg" msgid="4575787816055205600">"<xliff:g id="NUM_MISSED_CALLS">%s</xliff:g> пропуснати обаждания"</string>
diff --git a/res/values-ca/strings.xml b/res/values-ca/strings.xml
index 072b610..6a9aa2d 100644
--- a/res/values-ca/strings.xml
+++ b/res/values-ca/strings.xml
@@ -395,6 +395,7 @@
     <string name="card_title_hanging_up" msgid="3999101620995182450">"S\'està penjant"</string>
     <string name="card_title_in_call" msgid="6346543933068225205">"En una trucada"</string>
     <string name="card_title_my_phone_number" msgid="112428362494434191">"El meu número és <xliff:g id="MY_PHONE_NUMBER">%s</xliff:g>"</string>
+    <string name="notification_dialing" msgid="2107666444937350731">"Marcatge"</string>
     <string name="notification_missedCallTitle" msgid="7554385905572364535">"Trucada perduda"</string>
     <string name="notification_missedCallsTitle" msgid="1361677948941502522">"Trucades perdudes"</string>
     <string name="notification_missedCallsMsg" msgid="4575787816055205600">"<xliff:g id="NUM_MISSED_CALLS">%s</xliff:g> trucades perdudes"</string>
diff --git a/res/values-cs/strings.xml b/res/values-cs/strings.xml
index 587ea69..af013e2 100644
--- a/res/values-cs/strings.xml
+++ b/res/values-cs/strings.xml
@@ -395,6 +395,7 @@
     <string name="card_title_hanging_up" msgid="3999101620995182450">"Zavěšování"</string>
     <string name="card_title_in_call" msgid="6346543933068225205">"Probíhá hovor"</string>
     <string name="card_title_my_phone_number" msgid="112428362494434191">"Moje číslo je <xliff:g id="MY_PHONE_NUMBER">%s</xliff:g>"</string>
+    <string name="notification_dialing" msgid="2107666444937350731">"Vytáčení"</string>
     <string name="notification_missedCallTitle" msgid="7554385905572364535">"Zmeškaný hovor"</string>
     <string name="notification_missedCallsTitle" msgid="1361677948941502522">"Zmeškané hovory"</string>
     <string name="notification_missedCallsMsg" msgid="4575787816055205600">"Zmeškané hovory: <xliff:g id="NUM_MISSED_CALLS">%s</xliff:g>."</string>
diff --git a/res/values-da/strings.xml b/res/values-da/strings.xml
index 8cbbd12..ac2441b 100644
--- a/res/values-da/strings.xml
+++ b/res/values-da/strings.xml
@@ -401,6 +401,7 @@
     <string name="card_title_hanging_up" msgid="3999101620995182450">"Lægger på"</string>
     <string name="card_title_in_call" msgid="6346543933068225205">"Opkald i gang"</string>
     <string name="card_title_my_phone_number" msgid="112428362494434191">"Mit nummer er <xliff:g id="MY_PHONE_NUMBER">%s</xliff:g>"</string>
+    <string name="notification_dialing" msgid="2107666444937350731">"Ringer op"</string>
     <string name="notification_missedCallTitle" msgid="7554385905572364535">"Ubesvarede opkald"</string>
     <string name="notification_missedCallsTitle" msgid="1361677948941502522">"Ubesvarede opkald"</string>
     <string name="notification_missedCallsMsg" msgid="4575787816055205600">"<xliff:g id="NUM_MISSED_CALLS">%s</xliff:g> ubesvarede opkald"</string>
diff --git a/res/values-de/strings.xml b/res/values-de/strings.xml
index b638884..74e8596 100644
--- a/res/values-de/strings.xml
+++ b/res/values-de/strings.xml
@@ -399,6 +399,7 @@
     <string name="card_title_hanging_up" msgid="3999101620995182450">"Auflegen"</string>
     <string name="card_title_in_call" msgid="6346543933068225205">"Anruf"</string>
     <string name="card_title_my_phone_number" msgid="112428362494434191">"Meine Nummer lautet <xliff:g id="MY_PHONE_NUMBER">%s</xliff:g>."</string>
+    <string name="notification_dialing" msgid="2107666444937350731">"Verbindung wird aufgebaut..."</string>
     <string name="notification_missedCallTitle" msgid="7554385905572364535">"Entgangener Anruf"</string>
     <string name="notification_missedCallsTitle" msgid="1361677948941502522">"Entgangene Anrufe"</string>
     <string name="notification_missedCallsMsg" msgid="4575787816055205600">"<xliff:g id="NUM_MISSED_CALLS">%s</xliff:g> entgangene Anrufe"</string>
diff --git a/res/values-el/strings.xml b/res/values-el/strings.xml
index 78679e1..6bf050b 100644
--- a/res/values-el/strings.xml
+++ b/res/values-el/strings.xml
@@ -395,6 +395,7 @@
     <string name="card_title_hanging_up" msgid="3999101620995182450">"Κλείσιμο γραμμής"</string>
     <string name="card_title_in_call" msgid="6346543933068225205">"Σε κλήση"</string>
     <string name="card_title_my_phone_number" msgid="112428362494434191">"Ο αριθμός μου είναι <xliff:g id="MY_PHONE_NUMBER">%s</xliff:g>"</string>
+    <string name="notification_dialing" msgid="2107666444937350731">"Κλήση"</string>
     <string name="notification_missedCallTitle" msgid="7554385905572364535">"Αναπάντητη κλήση"</string>
     <string name="notification_missedCallsTitle" msgid="1361677948941502522">"Αναπάντητες κλήσεις"</string>
     <string name="notification_missedCallsMsg" msgid="4575787816055205600">"<xliff:g id="NUM_MISSED_CALLS">%s</xliff:g> αναπάντητες κλήσεις"</string>
diff --git a/res/values-en-rGB/strings.xml b/res/values-en-rGB/strings.xml
index ac52314..27a116d 100644
--- a/res/values-en-rGB/strings.xml
+++ b/res/values-en-rGB/strings.xml
@@ -395,6 +395,7 @@
     <string name="card_title_hanging_up" msgid="3999101620995182450">"Hanging up"</string>
     <string name="card_title_in_call" msgid="6346543933068225205">"In call"</string>
     <string name="card_title_my_phone_number" msgid="112428362494434191">"My number is <xliff:g id="MY_PHONE_NUMBER">%s</xliff:g>"</string>
+    <string name="notification_dialing" msgid="2107666444937350731">"Dialling"</string>
     <string name="notification_missedCallTitle" msgid="7554385905572364535">"Missed call"</string>
     <string name="notification_missedCallsTitle" msgid="1361677948941502522">"Missed calls"</string>
     <string name="notification_missedCallsMsg" msgid="4575787816055205600">"<xliff:g id="NUM_MISSED_CALLS">%s</xliff:g> missed calls"</string>
diff --git a/res/values-es-rUS/strings.xml b/res/values-es-rUS/strings.xml
index 6db20ee..316e086 100644
--- a/res/values-es-rUS/strings.xml
+++ b/res/values-es-rUS/strings.xml
@@ -395,6 +395,7 @@
     <string name="card_title_hanging_up" msgid="3999101620995182450">"Colgando"</string>
     <string name="card_title_in_call" msgid="6346543933068225205">"En llamada"</string>
     <string name="card_title_my_phone_number" msgid="112428362494434191">"Mi número es <xliff:g id="MY_PHONE_NUMBER">%s</xliff:g>"</string>
+    <string name="notification_dialing" msgid="2107666444937350731">"Marcando"</string>
     <string name="notification_missedCallTitle" msgid="7554385905572364535">"Llamada perdida"</string>
     <string name="notification_missedCallsTitle" msgid="1361677948941502522">"Llamadas perdidas"</string>
     <string name="notification_missedCallsMsg" msgid="4575787816055205600">"<xliff:g id="NUM_MISSED_CALLS">%s</xliff:g> llamadas perdidas"</string>
diff --git a/res/values-es/strings.xml b/res/values-es/strings.xml
index bd6946d..21fb011 100644
--- a/res/values-es/strings.xml
+++ b/res/values-es/strings.xml
@@ -399,6 +399,7 @@
     <string name="card_title_hanging_up" msgid="3999101620995182450">"Colgando"</string>
     <string name="card_title_in_call" msgid="6346543933068225205">"Llamada entrante"</string>
     <string name="card_title_my_phone_number" msgid="112428362494434191">"Mi número es <xliff:g id="MY_PHONE_NUMBER">%s</xliff:g>."</string>
+    <string name="notification_dialing" msgid="2107666444937350731">"Llamando..."</string>
     <string name="notification_missedCallTitle" msgid="7554385905572364535">"Llamada perdida"</string>
     <string name="notification_missedCallsTitle" msgid="1361677948941502522">"Llamadas perdidas"</string>
     <string name="notification_missedCallsMsg" msgid="4575787816055205600">"<xliff:g id="NUM_MISSED_CALLS">%s</xliff:g> llamadas perdidas"</string>
diff --git a/res/values-et/strings.xml b/res/values-et/strings.xml
index 7f934d0..1755314 100644
--- a/res/values-et/strings.xml
+++ b/res/values-et/strings.xml
@@ -395,6 +395,7 @@
     <string name="card_title_hanging_up" msgid="3999101620995182450">"Lõpetamisel"</string>
     <string name="card_title_in_call" msgid="6346543933068225205">"Kõne"</string>
     <string name="card_title_my_phone_number" msgid="112428362494434191">"Minu number on <xliff:g id="MY_PHONE_NUMBER">%s</xliff:g>"</string>
+    <string name="notification_dialing" msgid="2107666444937350731">"Valimine"</string>
     <string name="notification_missedCallTitle" msgid="7554385905572364535">"Vastamata kõne"</string>
     <string name="notification_missedCallsTitle" msgid="1361677948941502522">"Vastamata kõned"</string>
     <string name="notification_missedCallsMsg" msgid="4575787816055205600">"<xliff:g id="NUM_MISSED_CALLS">%s</xliff:g> vastamata kõnet"</string>
diff --git a/res/values-fa/strings.xml b/res/values-fa/strings.xml
index 1163ebc..26da88e 100644
--- a/res/values-fa/strings.xml
+++ b/res/values-fa/strings.xml
@@ -395,6 +395,7 @@
     <string name="card_title_hanging_up" msgid="3999101620995182450">"قطع تماس"</string>
     <string name="card_title_in_call" msgid="6346543933068225205">"در تماس"</string>
     <string name="card_title_my_phone_number" msgid="112428362494434191">"شماره من <xliff:g id="MY_PHONE_NUMBER">%s</xliff:g> است"</string>
+    <string name="notification_dialing" msgid="2107666444937350731">"شماره‌گیری"</string>
     <string name="notification_missedCallTitle" msgid="7554385905572364535">"تماس بی پاسخ"</string>
     <string name="notification_missedCallsTitle" msgid="1361677948941502522">"تماس‌های بی پاسخ"</string>
     <string name="notification_missedCallsMsg" msgid="4575787816055205600">"<xliff:g id="NUM_MISSED_CALLS">%s</xliff:g> تماس بی پاسخ"</string>
diff --git a/res/values-fi/strings.xml b/res/values-fi/strings.xml
index 1587076..be763c4 100644
--- a/res/values-fi/strings.xml
+++ b/res/values-fi/strings.xml
@@ -399,6 +399,7 @@
     <string name="card_title_hanging_up" msgid="3999101620995182450">"Katkaistaan"</string>
     <string name="card_title_in_call" msgid="6346543933068225205">"Puhelun aikana"</string>
     <string name="card_title_my_phone_number" msgid="112428362494434191">"Numeroni on <xliff:g id="MY_PHONE_NUMBER">%s</xliff:g>"</string>
+    <string name="notification_dialing" msgid="2107666444937350731">"Soitetaan"</string>
     <string name="notification_missedCallTitle" msgid="7554385905572364535">"Vastaamatta jäänyt puhelu"</string>
     <string name="notification_missedCallsTitle" msgid="1361677948941502522">"Vastaamattomat puhelut"</string>
     <string name="notification_missedCallsMsg" msgid="4575787816055205600">"<xliff:g id="NUM_MISSED_CALLS">%s</xliff:g> vastaamatonta puhelua"</string>
diff --git a/res/values-fr/strings.xml b/res/values-fr/strings.xml
index 953a44e..4f96455 100644
--- a/res/values-fr/strings.xml
+++ b/res/values-fr/strings.xml
@@ -395,6 +395,7 @@
     <string name="card_title_hanging_up" msgid="3999101620995182450">"Fin de l\'appel.."</string>
     <string name="card_title_in_call" msgid="6346543933068225205">"Appel en cours"</string>
     <string name="card_title_my_phone_number" msgid="112428362494434191">"Mon numéro est le <xliff:g id="MY_PHONE_NUMBER">%s</xliff:g>"</string>
+    <string name="notification_dialing" msgid="2107666444937350731">"Numérotation en cours…"</string>
     <string name="notification_missedCallTitle" msgid="7554385905572364535">"Appel manqué"</string>
     <string name="notification_missedCallsTitle" msgid="1361677948941502522">"Appels manqués"</string>
     <string name="notification_missedCallsMsg" msgid="4575787816055205600">"<xliff:g id="NUM_MISSED_CALLS">%s</xliff:g> appels manqués"</string>
diff --git a/res/values-hi/strings.xml b/res/values-hi/strings.xml
index 0880230..86de7d3 100644
--- a/res/values-hi/strings.xml
+++ b/res/values-hi/strings.xml
@@ -395,6 +395,7 @@
     <string name="card_title_hanging_up" msgid="3999101620995182450">"बंद कर रहा है"</string>
     <string name="card_title_in_call" msgid="6346543933068225205">"कॉल में"</string>
     <string name="card_title_my_phone_number" msgid="112428362494434191">"मेरा नंबर <xliff:g id="MY_PHONE_NUMBER">%s</xliff:g> है"</string>
+    <string name="notification_dialing" msgid="2107666444937350731">"डायल हो रहा है"</string>
     <string name="notification_missedCallTitle" msgid="7554385905572364535">"छूटी कॉल"</string>
     <string name="notification_missedCallsTitle" msgid="1361677948941502522">"छूटी कॉल"</string>
     <string name="notification_missedCallsMsg" msgid="4575787816055205600">"<xliff:g id="NUM_MISSED_CALLS">%s</xliff:g> छूटी कॉल"</string>
diff --git a/res/values-hr/strings.xml b/res/values-hr/strings.xml
index eda2ac7..e3f6d31 100644
--- a/res/values-hr/strings.xml
+++ b/res/values-hr/strings.xml
@@ -395,6 +395,7 @@
     <string name="card_title_hanging_up" msgid="3999101620995182450">"Prekidanje veze"</string>
     <string name="card_title_in_call" msgid="6346543933068225205">"Poziv u tijeku"</string>
     <string name="card_title_my_phone_number" msgid="112428362494434191">"Moj broj je <xliff:g id="MY_PHONE_NUMBER">%s</xliff:g>"</string>
+    <string name="notification_dialing" msgid="2107666444937350731">"Biranje broja"</string>
     <string name="notification_missedCallTitle" msgid="7554385905572364535">"Propušteni poziv"</string>
     <string name="notification_missedCallsTitle" msgid="1361677948941502522">"Propušteni pozivi"</string>
     <string name="notification_missedCallsMsg" msgid="4575787816055205600">"Broj propuštenih poziva: <xliff:g id="NUM_MISSED_CALLS">%s</xliff:g>"</string>
diff --git a/res/values-hu/strings.xml b/res/values-hu/strings.xml
index 4319e01..261dba2 100644
--- a/res/values-hu/strings.xml
+++ b/res/values-hu/strings.xml
@@ -395,6 +395,7 @@
     <string name="card_title_hanging_up" msgid="3999101620995182450">"Megszakítás"</string>
     <string name="card_title_in_call" msgid="6346543933068225205">"Hívásban"</string>
     <string name="card_title_my_phone_number" msgid="112428362494434191">"A számom: <xliff:g id="MY_PHONE_NUMBER">%s</xliff:g>"</string>
+    <string name="notification_dialing" msgid="2107666444937350731">"Tárcsázás"</string>
     <string name="notification_missedCallTitle" msgid="7554385905572364535">"Nem fogadott hívás"</string>
     <string name="notification_missedCallsTitle" msgid="1361677948941502522">"Nem fogadott hívások"</string>
     <string name="notification_missedCallsMsg" msgid="4575787816055205600">"<xliff:g id="NUM_MISSED_CALLS">%s</xliff:g> nem fogadott hívás"</string>
diff --git a/res/values-in/strings.xml b/res/values-in/strings.xml
index e0c4af8..b660a3e 100644
--- a/res/values-in/strings.xml
+++ b/res/values-in/strings.xml
@@ -395,6 +395,7 @@
     <string name="card_title_hanging_up" msgid="3999101620995182450">"Menutup panggilan"</string>
     <string name="card_title_in_call" msgid="6346543933068225205">"Sedang dalam panggilan"</string>
     <string name="card_title_my_phone_number" msgid="112428362494434191">"Nomor saya <xliff:g id="MY_PHONE_NUMBER">%s</xliff:g>"</string>
+    <string name="notification_dialing" msgid="2107666444937350731">"Memanggil"</string>
     <string name="notification_missedCallTitle" msgid="7554385905572364535">"Panggilan tak terjawab"</string>
     <string name="notification_missedCallsTitle" msgid="1361677948941502522">"Panggilan tak terjawab"</string>
     <string name="notification_missedCallsMsg" msgid="4575787816055205600">"<xliff:g id="NUM_MISSED_CALLS">%s</xliff:g> panggilan tak terjawab"</string>
diff --git a/res/values-it/strings.xml b/res/values-it/strings.xml
index c792049..442aceb 100644
--- a/res/values-it/strings.xml
+++ b/res/values-it/strings.xml
@@ -399,6 +399,7 @@
     <string name="card_title_hanging_up" msgid="3999101620995182450">"In fase di chiusura"</string>
     <string name="card_title_in_call" msgid="6346543933068225205">"Chiamata"</string>
     <string name="card_title_my_phone_number" msgid="112428362494434191">"Il mio numero è <xliff:g id="MY_PHONE_NUMBER">%s</xliff:g>"</string>
+    <string name="notification_dialing" msgid="2107666444937350731">"Chiamata in corso"</string>
     <string name="notification_missedCallTitle" msgid="7554385905572364535">"Chiamata senza risposta"</string>
     <string name="notification_missedCallsTitle" msgid="1361677948941502522">"Chiamate senza risposta"</string>
     <string name="notification_missedCallsMsg" msgid="4575787816055205600">"<xliff:g id="NUM_MISSED_CALLS">%s</xliff:g> chiamate senza risposta"</string>
diff --git a/res/values-iw/strings.xml b/res/values-iw/strings.xml
index 3bf8f95..193ebe6 100644
--- a/res/values-iw/strings.xml
+++ b/res/values-iw/strings.xml
@@ -395,6 +395,7 @@
     <string name="card_title_hanging_up" msgid="3999101620995182450">"מנתק"</string>
     <string name="card_title_in_call" msgid="6346543933068225205">"בשיחה"</string>
     <string name="card_title_my_phone_number" msgid="112428362494434191">"המספר שלי הוא <xliff:g id="MY_PHONE_NUMBER">%s</xliff:g>"</string>
+    <string name="notification_dialing" msgid="2107666444937350731">"מחייג"</string>
     <string name="notification_missedCallTitle" msgid="7554385905572364535">"שיחה שלא נענתה"</string>
     <string name="notification_missedCallsTitle" msgid="1361677948941502522">"שיחות שלא נענו"</string>
     <string name="notification_missedCallsMsg" msgid="4575787816055205600">"<xliff:g id="NUM_MISSED_CALLS">%s</xliff:g> שיחות שלא נענו"</string>
diff --git a/res/values-ja/strings.xml b/res/values-ja/strings.xml
index fd97dcf..daf0844 100644
--- a/res/values-ja/strings.xml
+++ b/res/values-ja/strings.xml
@@ -395,6 +395,7 @@
     <string name="card_title_hanging_up" msgid="3999101620995182450">"通話終了"</string>
     <string name="card_title_in_call" msgid="6346543933068225205">"着信"</string>
     <string name="card_title_my_phone_number" msgid="112428362494434191">"この電話の番号: <xliff:g id="MY_PHONE_NUMBER">%s</xliff:g>"</string>
+    <string name="notification_dialing" msgid="2107666444937350731">"発信中"</string>
     <string name="notification_missedCallTitle" msgid="7554385905572364535">"不在着信"</string>
     <string name="notification_missedCallsTitle" msgid="1361677948941502522">"不在着信"</string>
     <string name="notification_missedCallsMsg" msgid="4575787816055205600">"不在着信<xliff:g id="NUM_MISSED_CALLS">%s</xliff:g>件"</string>
diff --git a/res/values-ko/strings.xml b/res/values-ko/strings.xml
index 9ed70a3..982b863 100644
--- a/res/values-ko/strings.xml
+++ b/res/values-ko/strings.xml
@@ -395,6 +395,7 @@
     <string name="card_title_hanging_up" msgid="3999101620995182450">"전화 끊는 중"</string>
     <string name="card_title_in_call" msgid="6346543933068225205">"통화 상태"</string>
     <string name="card_title_my_phone_number" msgid="112428362494434191">"내 전화번호는 <xliff:g id="MY_PHONE_NUMBER">%s</xliff:g>입니다."</string>
+    <string name="notification_dialing" msgid="2107666444937350731">"전화 거는 중"</string>
     <string name="notification_missedCallTitle" msgid="7554385905572364535">"부재중 전화"</string>
     <string name="notification_missedCallsTitle" msgid="1361677948941502522">"부재중 통화"</string>
     <string name="notification_missedCallsMsg" msgid="4575787816055205600">"부재중 통화 <xliff:g id="NUM_MISSED_CALLS">%s</xliff:g>통"</string>
diff --git a/res/values-land/dimens.xml b/res/values-land/dimens.xml
index 56ad159..9eb531d 100644
--- a/res/values-land/dimens.xml
+++ b/res/values-land/dimens.xml
@@ -15,4 +15,7 @@
 -->
 <resources>
     <dimen name="emergency_dialer_digits_height">66dip</dimen>
+
+    <!-- Height of the "call banner" overlay on bottom of the call_card -->
+    <dimen name="call_banner_height">@dimen/in_call_end_button_height</dimen>
 </resources>
diff --git a/res/values-land/styles.xml b/res/values-land/styles.xml
new file mode 100644
index 0000000..0626a15
--- /dev/null
+++ b/res/values-land/styles.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2012 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<resources>
+    <style name="PrimaryCallInfoPrimaryCallBanner">
+        <item name="android:layout_alignParentBottom">true</item>
+    </style>
+    <style name="PrimaryCallInfoSecondaryInfoContainer">
+        <item name="android:layout_above">@id/primary_call_banner</item>
+    </style>
+
+    <style name="SecondaryCallInfoSecondaryCallName">
+        <item name="android:layout_gravity">bottom|left</item>
+    </style>
+    <style name="SecondaryCallInfoSecondaryCallStatus">
+        <item name="android:layout_gravity">bottom|right</item>
+    </style>
+</resources>
diff --git a/res/values-lt/strings.xml b/res/values-lt/strings.xml
index 67c7e61..b4d8269 100644
--- a/res/values-lt/strings.xml
+++ b/res/values-lt/strings.xml
@@ -395,6 +395,7 @@
     <string name="card_title_hanging_up" msgid="3999101620995182450">"Baigiamas pokalbis"</string>
     <string name="card_title_in_call" msgid="6346543933068225205">"Skambinant"</string>
     <string name="card_title_my_phone_number" msgid="112428362494434191">"Mano numeris: <xliff:g id="MY_PHONE_NUMBER">%s</xliff:g>"</string>
+    <string name="notification_dialing" msgid="2107666444937350731">"Renkamas numeris"</string>
     <string name="notification_missedCallTitle" msgid="7554385905572364535">"Praleistas skambutis"</string>
     <string name="notification_missedCallsTitle" msgid="1361677948941502522">"Praleisti skambučiai"</string>
     <string name="notification_missedCallsMsg" msgid="4575787816055205600">"<xliff:g id="NUM_MISSED_CALLS">%s</xliff:g> praleisti (-ų) skambučiai (-ų)"</string>
diff --git a/res/values-lv/strings.xml b/res/values-lv/strings.xml
index c2c8594..9893974 100644
--- a/res/values-lv/strings.xml
+++ b/res/values-lv/strings.xml
@@ -397,6 +397,7 @@
     <string name="card_title_hanging_up" msgid="3999101620995182450">"Notiek klausules nolikšana"</string>
     <string name="card_title_in_call" msgid="6346543933068225205">"Notiek saruna"</string>
     <string name="card_title_my_phone_number" msgid="112428362494434191">"Mans tālruņa numurs: <xliff:g id="MY_PHONE_NUMBER">%s</xliff:g>"</string>
+    <string name="notification_dialing" msgid="2107666444937350731">"Notiek numura sastādīšana"</string>
     <string name="notification_missedCallTitle" msgid="7554385905572364535">"Neatbildēts zvans"</string>
     <string name="notification_missedCallsTitle" msgid="1361677948941502522">"Neatbildētie zvani"</string>
     <string name="notification_missedCallsMsg" msgid="4575787816055205600">"<xliff:g id="NUM_MISSED_CALLS">%s</xliff:g> neatbildēts(-i) zvans(-i)"</string>
diff --git a/res/values-ms/strings.xml b/res/values-ms/strings.xml
index 7cdb49f..92536c2 100644
--- a/res/values-ms/strings.xml
+++ b/res/values-ms/strings.xml
@@ -395,6 +395,7 @@
     <string name="card_title_hanging_up" msgid="3999101620995182450">"Menamatkan panggilan"</string>
     <string name="card_title_in_call" msgid="6346543933068225205">"Dalam panggilan"</string>
     <string name="card_title_my_phone_number" msgid="112428362494434191">"Nombor saya ialah <xliff:g id="MY_PHONE_NUMBER">%s</xliff:g>"</string>
+    <string name="notification_dialing" msgid="2107666444937350731">"Mendail"</string>
     <string name="notification_missedCallTitle" msgid="7554385905572364535">"Panggilan tidak dijawab"</string>
     <string name="notification_missedCallsTitle" msgid="1361677948941502522">"Panggilan tidak dijawab"</string>
     <string name="notification_missedCallsMsg" msgid="4575787816055205600">"<xliff:g id="NUM_MISSED_CALLS">%s</xliff:g> panggilan tidak dijawab"</string>
diff --git a/res/values-nb/strings.xml b/res/values-nb/strings.xml
index a706730..4cd6ee4 100644
--- a/res/values-nb/strings.xml
+++ b/res/values-nb/strings.xml
@@ -401,6 +401,7 @@
     <string name="card_title_hanging_up" msgid="3999101620995182450">"Legger på"</string>
     <string name="card_title_in_call" msgid="6346543933068225205">"Samtale pågår"</string>
     <string name="card_title_my_phone_number" msgid="112428362494434191">"Nummeret mitt er <xliff:g id="MY_PHONE_NUMBER">%s</xliff:g>"</string>
+    <string name="notification_dialing" msgid="2107666444937350731">"Slår nummeret"</string>
     <string name="notification_missedCallTitle" msgid="7554385905572364535">"Tapt anrop"</string>
     <string name="notification_missedCallsTitle" msgid="1361677948941502522">"Tapte anrop"</string>
     <string name="notification_missedCallsMsg" msgid="4575787816055205600">"<xliff:g id="NUM_MISSED_CALLS">%s</xliff:g> tapte anrop"</string>
diff --git a/res/values-nl/strings.xml b/res/values-nl/strings.xml
index 3b981dc..efe72ba 100644
--- a/res/values-nl/strings.xml
+++ b/res/values-nl/strings.xml
@@ -395,6 +395,7 @@
     <string name="card_title_hanging_up" msgid="3999101620995182450">"Ophangen"</string>
     <string name="card_title_in_call" msgid="6346543933068225205">"Actieve oproep"</string>
     <string name="card_title_my_phone_number" msgid="112428362494434191">"Mijn nummer is <xliff:g id="MY_PHONE_NUMBER">%s</xliff:g>"</string>
+    <string name="notification_dialing" msgid="2107666444937350731">"Kiezen"</string>
     <string name="notification_missedCallTitle" msgid="7554385905572364535">"Gemiste oproep"</string>
     <string name="notification_missedCallsTitle" msgid="1361677948941502522">"Gemiste oproepen"</string>
     <string name="notification_missedCallsMsg" msgid="4575787816055205600">"<xliff:g id="NUM_MISSED_CALLS">%s</xliff:g> gemiste oproepen"</string>
diff --git a/res/values-pl/strings.xml b/res/values-pl/strings.xml
index 0a65331..15deb2e 100644
--- a/res/values-pl/strings.xml
+++ b/res/values-pl/strings.xml
@@ -395,6 +395,7 @@
     <string name="card_title_hanging_up" msgid="3999101620995182450">"Trwa rozłączanie"</string>
     <string name="card_title_in_call" msgid="6346543933068225205">"Trwa połączenie"</string>
     <string name="card_title_my_phone_number" msgid="112428362494434191">"Mój numer to <xliff:g id="MY_PHONE_NUMBER">%s</xliff:g>"</string>
+    <string name="notification_dialing" msgid="2107666444937350731">"Trwa wybieranie numeru"</string>
     <string name="notification_missedCallTitle" msgid="7554385905572364535">"Nieodebrane połączenie"</string>
     <string name="notification_missedCallsTitle" msgid="1361677948941502522">"Połączenia nieodebrane"</string>
     <string name="notification_missedCallsMsg" msgid="4575787816055205600">"<xliff:g id="NUM_MISSED_CALLS">%s</xliff:g> nieodebranych połączeń"</string>
diff --git a/res/values-pt-rPT/strings.xml b/res/values-pt-rPT/strings.xml
index e9a16ec..34fdc61 100644
--- a/res/values-pt-rPT/strings.xml
+++ b/res/values-pt-rPT/strings.xml
@@ -395,6 +395,7 @@
     <string name="card_title_hanging_up" msgid="3999101620995182450">"A desligar"</string>
     <string name="card_title_in_call" msgid="6346543933068225205">"A chamar"</string>
     <string name="card_title_my_phone_number" msgid="112428362494434191">"O meu número é <xliff:g id="MY_PHONE_NUMBER">%s</xliff:g>"</string>
+    <string name="notification_dialing" msgid="2107666444937350731">"A marcar"</string>
     <string name="notification_missedCallTitle" msgid="7554385905572364535">"Chamada não atendida"</string>
     <string name="notification_missedCallsTitle" msgid="1361677948941502522">"Chamadas não atendidas"</string>
     <string name="notification_missedCallsMsg" msgid="4575787816055205600">"<xliff:g id="NUM_MISSED_CALLS">%s</xliff:g> chamadas não atendidas"</string>
diff --git a/res/values-pt/strings.xml b/res/values-pt/strings.xml
index 05dc83f..177ba64 100644
--- a/res/values-pt/strings.xml
+++ b/res/values-pt/strings.xml
@@ -395,6 +395,7 @@
     <string name="card_title_hanging_up" msgid="3999101620995182450">"Desligando"</string>
     <string name="card_title_in_call" msgid="6346543933068225205">"Em chamada"</string>
     <string name="card_title_my_phone_number" msgid="112428362494434191">"Meu número é <xliff:g id="MY_PHONE_NUMBER">%s</xliff:g>"</string>
+    <string name="notification_dialing" msgid="2107666444937350731">"Discando"</string>
     <string name="notification_missedCallTitle" msgid="7554385905572364535">"Chamada perdida"</string>
     <string name="notification_missedCallsTitle" msgid="1361677948941502522">"Chamadas perdidas"</string>
     <string name="notification_missedCallsMsg" msgid="4575787816055205600">"<xliff:g id="NUM_MISSED_CALLS">%s</xliff:g> chamadas perdidas"</string>
diff --git a/res/values-rm/strings.xml b/res/values-rm/strings.xml
index 422022d..31002f9 100644
--- a/res/values-rm/strings.xml
+++ b/res/values-rm/strings.xml
@@ -463,6 +463,8 @@
     <string name="card_title_in_call" msgid="6346543933068225205">"Clom"</string>
     <!-- no translation found for card_title_my_phone_number (112428362494434191) -->
     <skip />
+    <!-- no translation found for notification_dialing (2107666444937350731) -->
+    <skip />
     <string name="notification_missedCallTitle" msgid="7554385905572364535">"Clom manchentà"</string>
     <string name="notification_missedCallsTitle" msgid="1361677948941502522">"Cloms manchentads"</string>
     <string name="notification_missedCallsMsg" msgid="4575787816055205600">"<xliff:g id="NUM_MISSED_CALLS">%s</xliff:g> cloms manchentads"</string>
diff --git a/res/values-ro/strings.xml b/res/values-ro/strings.xml
index 6840427..3611653 100644
--- a/res/values-ro/strings.xml
+++ b/res/values-ro/strings.xml
@@ -395,6 +395,7 @@
     <string name="card_title_hanging_up" msgid="3999101620995182450">"Se închide telefonul"</string>
     <string name="card_title_in_call" msgid="6346543933068225205">"În timpul apelului"</string>
     <string name="card_title_my_phone_number" msgid="112428362494434191">"Numărul meu este <xliff:g id="MY_PHONE_NUMBER">%s</xliff:g>"</string>
+    <string name="notification_dialing" msgid="2107666444937350731">"Apelează"</string>
     <string name="notification_missedCallTitle" msgid="7554385905572364535">"Apel nepreluat"</string>
     <string name="notification_missedCallsTitle" msgid="1361677948941502522">"Apeluri nepreluate"</string>
     <string name="notification_missedCallsMsg" msgid="4575787816055205600">"<xliff:g id="NUM_MISSED_CALLS">%s</xliff:g> (de) apeluri nepreluate"</string>
diff --git a/res/values-ru/strings.xml b/res/values-ru/strings.xml
index 8909248..ef165ee 100644
--- a/res/values-ru/strings.xml
+++ b/res/values-ru/strings.xml
@@ -397,6 +397,7 @@
     <string name="card_title_hanging_up" msgid="3999101620995182450">"Завершение разговора"</string>
     <string name="card_title_in_call" msgid="6346543933068225205">"Поступающий вызов"</string>
     <string name="card_title_my_phone_number" msgid="112428362494434191">"Мой номер: <xliff:g id="MY_PHONE_NUMBER">%s</xliff:g>"</string>
+    <string name="notification_dialing" msgid="2107666444937350731">"Набор номера"</string>
     <string name="notification_missedCallTitle" msgid="7554385905572364535">"Пропущенный вызов"</string>
     <string name="notification_missedCallsTitle" msgid="1361677948941502522">"Пропущенные вызовы"</string>
     <string name="notification_missedCallsMsg" msgid="4575787816055205600">"Пропущенных вызовов: <xliff:g id="NUM_MISSED_CALLS">%s</xliff:g>"</string>
diff --git a/res/values-sk/strings.xml b/res/values-sk/strings.xml
index 112e3bb..080a0b3 100644
--- a/res/values-sk/strings.xml
+++ b/res/values-sk/strings.xml
@@ -395,6 +395,7 @@
     <string name="card_title_hanging_up" msgid="3999101620995182450">"Ukončovanie hovoru"</string>
     <string name="card_title_in_call" msgid="6346543933068225205">"Prebieha hovor"</string>
     <string name="card_title_my_phone_number" msgid="112428362494434191">"Moje číslo je <xliff:g id="MY_PHONE_NUMBER">%s</xliff:g>"</string>
+    <string name="notification_dialing" msgid="2107666444937350731">"Vytáčanie"</string>
     <string name="notification_missedCallTitle" msgid="7554385905572364535">"Zmeškaný hovor"</string>
     <string name="notification_missedCallsTitle" msgid="1361677948941502522">"Zmeškané hovory"</string>
     <string name="notification_missedCallsMsg" msgid="4575787816055205600">"Zmeškané hovory: <xliff:g id="NUM_MISSED_CALLS">%s</xliff:g>."</string>
diff --git a/res/values-sl/strings.xml b/res/values-sl/strings.xml
index 368b43e..057993d 100644
--- a/res/values-sl/strings.xml
+++ b/res/values-sl/strings.xml
@@ -395,6 +395,7 @@
     <string name="card_title_hanging_up" msgid="3999101620995182450">"Prekinitev"</string>
     <string name="card_title_in_call" msgid="6346543933068225205">"Dohodni klic"</string>
     <string name="card_title_my_phone_number" msgid="112428362494434191">"Moja številka je <xliff:g id="MY_PHONE_NUMBER">%s</xliff:g>"</string>
+    <string name="notification_dialing" msgid="2107666444937350731">"Klicanje"</string>
     <string name="notification_missedCallTitle" msgid="7554385905572364535">"Neodgovorjeni klic"</string>
     <string name="notification_missedCallsTitle" msgid="1361677948941502522">"Neodgovorjeni klici"</string>
     <string name="notification_missedCallsMsg" msgid="4575787816055205600">"<xliff:g id="NUM_MISSED_CALLS">%s</xliff:g> neodgovorjenih klicev"</string>
diff --git a/res/values-sr/strings.xml b/res/values-sr/strings.xml
index a5a0f2c..6c47923 100644
--- a/res/values-sr/strings.xml
+++ b/res/values-sr/strings.xml
@@ -395,6 +395,7 @@
     <string name="card_title_hanging_up" msgid="3999101620995182450">"Прекид везе"</string>
     <string name="card_title_in_call" msgid="6346543933068225205">"Има позив"</string>
     <string name="card_title_my_phone_number" msgid="112428362494434191">"Мој број је <xliff:g id="MY_PHONE_NUMBER">%s</xliff:g>"</string>
+    <string name="notification_dialing" msgid="2107666444937350731">"Бирање"</string>
     <string name="notification_missedCallTitle" msgid="7554385905572364535">"Пропуштен позив"</string>
     <string name="notification_missedCallsTitle" msgid="1361677948941502522">"Пропуштени позиви"</string>
     <string name="notification_missedCallsMsg" msgid="4575787816055205600">"Број пропуштених позива: <xliff:g id="NUM_MISSED_CALLS">%s</xliff:g>"</string>
diff --git a/res/values-sv/strings.xml b/res/values-sv/strings.xml
index 1bc649e..e8366a4 100644
--- a/res/values-sv/strings.xml
+++ b/res/values-sv/strings.xml
@@ -401,6 +401,7 @@
     <string name="card_title_hanging_up" msgid="3999101620995182450">"Lägger på"</string>
     <string name="card_title_in_call" msgid="6346543933068225205">"I samtal"</string>
     <string name="card_title_my_phone_number" msgid="112428362494434191">"Mitt nummer är <xliff:g id="MY_PHONE_NUMBER">%s</xliff:g>"</string>
+    <string name="notification_dialing" msgid="2107666444937350731">"Ringer"</string>
     <string name="notification_missedCallTitle" msgid="7554385905572364535">"Missat samtal"</string>
     <string name="notification_missedCallsTitle" msgid="1361677948941502522">"Missade samtal"</string>
     <string name="notification_missedCallsMsg" msgid="4575787816055205600">"<xliff:g id="NUM_MISSED_CALLS">%s</xliff:g> missade samtal"</string>
diff --git a/res/values-sw/strings.xml b/res/values-sw/strings.xml
index 8de488f..f38b2a0 100644
--- a/res/values-sw/strings.xml
+++ b/res/values-sw/strings.xml
@@ -395,6 +395,7 @@
     <string name="card_title_hanging_up" msgid="3999101620995182450">"Kukata simu"</string>
     <string name="card_title_in_call" msgid="6346543933068225205">"Katika simu"</string>
     <string name="card_title_my_phone_number" msgid="112428362494434191">"Nambari yangu ni <xliff:g id="MY_PHONE_NUMBER">%s</xliff:g>"</string>
+    <string name="notification_dialing" msgid="2107666444937350731">"Inapiga"</string>
     <string name="notification_missedCallTitle" msgid="7554385905572364535">"Simu isiyojibiwa"</string>
     <string name="notification_missedCallsTitle" msgid="1361677948941502522">"Simu zisizojibiwa"</string>
     <string name="notification_missedCallsMsg" msgid="4575787816055205600">"<xliff:g id="NUM_MISSED_CALLS">%s</xliff:g> simu ambazo hazijajibiwa"</string>
diff --git a/res/values-th/strings.xml b/res/values-th/strings.xml
index a1b2dee..78f593d 100644
--- a/res/values-th/strings.xml
+++ b/res/values-th/strings.xml
@@ -395,6 +395,7 @@
     <string name="card_title_hanging_up" msgid="3999101620995182450">"กำลังวางสาย"</string>
     <string name="card_title_in_call" msgid="6346543933068225205">"กำลังใช้สาย"</string>
     <string name="card_title_my_phone_number" msgid="112428362494434191">"หมายเลขของฉันคือ <xliff:g id="MY_PHONE_NUMBER">%s</xliff:g>"</string>
+    <string name="notification_dialing" msgid="2107666444937350731">"กำลังโทรออก"</string>
     <string name="notification_missedCallTitle" msgid="7554385905572364535">"สายที่ไม่ได้รับ"</string>
     <string name="notification_missedCallsTitle" msgid="1361677948941502522">"สายที่ไม่ได้รับ"</string>
     <string name="notification_missedCallsMsg" msgid="4575787816055205600">"<xliff:g id="NUM_MISSED_CALLS">%s</xliff:g> สายที่ไม่ได้รับ"</string>
diff --git a/res/values-tl/strings.xml b/res/values-tl/strings.xml
index 2919f3d..eaa1968 100644
--- a/res/values-tl/strings.xml
+++ b/res/values-tl/strings.xml
@@ -395,6 +395,7 @@
     <string name="card_title_hanging_up" msgid="3999101620995182450">"Binababa"</string>
     <string name="card_title_in_call" msgid="6346543933068225205">"Nasa tawag"</string>
     <string name="card_title_my_phone_number" msgid="112428362494434191">"Ang aking numero ay <xliff:g id="MY_PHONE_NUMBER">%s</xliff:g>"</string>
+    <string name="notification_dialing" msgid="2107666444937350731">"Dina-dial"</string>
     <string name="notification_missedCallTitle" msgid="7554385905572364535">"Hindi nasagot na tawag"</string>
     <string name="notification_missedCallsTitle" msgid="1361677948941502522">"Mga hindi nasagot na tawag"</string>
     <string name="notification_missedCallsMsg" msgid="4575787816055205600">"<xliff:g id="NUM_MISSED_CALLS">%s</xliff:g> (na) hindi nasagot na tawag"</string>
diff --git a/res/values-tr/strings.xml b/res/values-tr/strings.xml
index 1567c0d..7f014a8 100644
--- a/res/values-tr/strings.xml
+++ b/res/values-tr/strings.xml
@@ -395,6 +395,7 @@
     <string name="card_title_hanging_up" msgid="3999101620995182450">"Sonlandırılıyor"</string>
     <string name="card_title_in_call" msgid="6346543933068225205">"Çağrı halinde"</string>
     <string name="card_title_my_phone_number" msgid="112428362494434191">"Numaram: <xliff:g id="MY_PHONE_NUMBER">%s</xliff:g>"</string>
+    <string name="notification_dialing" msgid="2107666444937350731">"Çevriliyor"</string>
     <string name="notification_missedCallTitle" msgid="7554385905572364535">"Cevapsız çağrı"</string>
     <string name="notification_missedCallsTitle" msgid="1361677948941502522">"Cevapsız çağrılar"</string>
     <string name="notification_missedCallsMsg" msgid="4575787816055205600">"<xliff:g id="NUM_MISSED_CALLS">%s</xliff:g> cevapsız çağrı"</string>
diff --git a/res/values-uk/strings.xml b/res/values-uk/strings.xml
index f92f403..068ba9e 100644
--- a/res/values-uk/strings.xml
+++ b/res/values-uk/strings.xml
@@ -395,6 +395,7 @@
     <string name="card_title_hanging_up" msgid="3999101620995182450">"Класти слухавку"</string>
     <string name="card_title_in_call" msgid="6346543933068225205">"Вхід. викл."</string>
     <string name="card_title_my_phone_number" msgid="112428362494434191">"Мій номер: <xliff:g id="MY_PHONE_NUMBER">%s</xliff:g>"</string>
+    <string name="notification_dialing" msgid="2107666444937350731">"Набір"</string>
     <string name="notification_missedCallTitle" msgid="7554385905572364535">"Пропущ. виклик"</string>
     <string name="notification_missedCallsTitle" msgid="1361677948941502522">"Пропущ. дзвінки"</string>
     <string name="notification_missedCallsMsg" msgid="4575787816055205600">"Пропущ. дзвінк: <xliff:g id="NUM_MISSED_CALLS">%s</xliff:g>"</string>
diff --git a/res/values-vi/strings.xml b/res/values-vi/strings.xml
index 5881f64..348819c 100644
--- a/res/values-vi/strings.xml
+++ b/res/values-vi/strings.xml
@@ -395,6 +395,7 @@
     <string name="card_title_hanging_up" msgid="3999101620995182450">"Kết thúc cuộc gọi"</string>
     <string name="card_title_in_call" msgid="6346543933068225205">"Đang trong cuộc gọi"</string>
     <string name="card_title_my_phone_number" msgid="112428362494434191">"Số điện thoại của tôi là <xliff:g id="MY_PHONE_NUMBER">%s</xliff:g>"</string>
+    <string name="notification_dialing" msgid="2107666444937350731">"Đang gọi"</string>
     <string name="notification_missedCallTitle" msgid="7554385905572364535">"Cuộc gọi nhỡ"</string>
     <string name="notification_missedCallsTitle" msgid="1361677948941502522">"Cuộc gọi nhỡ"</string>
     <string name="notification_missedCallsMsg" msgid="4575787816055205600">"<xliff:g id="NUM_MISSED_CALLS">%s</xliff:g> cuộc gọi nhỡ"</string>
diff --git a/res/values-zh-rCN/strings.xml b/res/values-zh-rCN/strings.xml
index 8896425..1d3aafa 100644
--- a/res/values-zh-rCN/strings.xml
+++ b/res/values-zh-rCN/strings.xml
@@ -395,6 +395,7 @@
     <string name="card_title_hanging_up" msgid="3999101620995182450">"正在挂断"</string>
     <string name="card_title_in_call" msgid="6346543933068225205">"正在通话"</string>
     <string name="card_title_my_phone_number" msgid="112428362494434191">"我的手机号码:<xliff:g id="MY_PHONE_NUMBER">%s</xliff:g>"</string>
+    <string name="notification_dialing" msgid="2107666444937350731">"正在拨号"</string>
     <string name="notification_missedCallTitle" msgid="7554385905572364535">"未接电话"</string>
     <string name="notification_missedCallsTitle" msgid="1361677948941502522">"未接电话"</string>
     <string name="notification_missedCallsMsg" msgid="4575787816055205600">"<xliff:g id="NUM_MISSED_CALLS">%s</xliff:g> 个未接电话"</string>
diff --git a/res/values-zh-rTW/strings.xml b/res/values-zh-rTW/strings.xml
index c0d1ae1..f17a251 100644
--- a/res/values-zh-rTW/strings.xml
+++ b/res/values-zh-rTW/strings.xml
@@ -401,6 +401,7 @@
     <string name="card_title_hanging_up" msgid="3999101620995182450">"掛斷電話"</string>
     <string name="card_title_in_call" msgid="6346543933068225205">"通話中"</string>
     <string name="card_title_my_phone_number" msgid="112428362494434191">"我的電話號碼:<xliff:g id="MY_PHONE_NUMBER">%s</xliff:g>"</string>
+    <string name="notification_dialing" msgid="2107666444937350731">"撥號中"</string>
     <string name="notification_missedCallTitle" msgid="7554385905572364535">"未接來電"</string>
     <string name="notification_missedCallsTitle" msgid="1361677948941502522">"未接來電"</string>
     <string name="notification_missedCallsMsg" msgid="4575787816055205600">"<xliff:g id="NUM_MISSED_CALLS">%s</xliff:g> 通未接來電"</string>
diff --git a/res/values-zu/strings.xml b/res/values-zu/strings.xml
index 518d029..d2db86f 100644
--- a/res/values-zu/strings.xml
+++ b/res/values-zu/strings.xml
@@ -399,6 +399,7 @@
     <string name="card_title_hanging_up" msgid="3999101620995182450">"Iyavala"</string>
     <string name="card_title_in_call" msgid="6346543933068225205">"Isecingweni"</string>
     <string name="card_title_my_phone_number" msgid="112428362494434191">"Inombolo yami ngu <xliff:g id="MY_PHONE_NUMBER">%s</xliff:g>"</string>
+    <string name="notification_dialing" msgid="2107666444937350731">"Iyadayela"</string>
     <string name="notification_missedCallTitle" msgid="7554385905572364535">"Ikholi ekulahlekele"</string>
     <string name="notification_missedCallsTitle" msgid="1361677948941502522">"Izincingo ezikulahlekele"</string>
     <string name="notification_missedCallsMsg" msgid="4575787816055205600">"<xliff:g id="NUM_MISSED_CALLS">%s</xliff:g> amakholi akulahlekele"</string>
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index 97a1496..5adfe52 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -41,7 +41,7 @@
     <!-- Height of the main row of in-call buttons. -->
     <dimen name="in_call_button_height">76dp</dimen>
 
-    <!-- Height of the in-call "End" button. -->
+    <!-- Height of the in-call "End" button. Match with Contact's dimens/call_button_height -->
     <dimen name="in_call_end_button_height">74dp</dimen>
 
     <!-- Width of buttons in the extra button row. -->
@@ -69,8 +69,12 @@
     <dimen name="dialpad_horizontal_margin">4dp</dimen>
     <dimen name="dialpad_vertical_margin">2dp</dimen>
     <dimen name="dialpad_digits_text_size">35sp</dimen>
+
     <!-- Just used in landscape mode -->
     <dimen name="emergency_dialer_digits_height">0px</dimen>
+    <dimen name="dialpad_center_margin">3dp</dimen>
+    <dimen name="dialpad_button_margin">3dp</dimen>
+
 
     <!-- Layout weight values for dialpad screen. These layouts will be used in one
          LinearLayout (dialpad_fragment.xml), configuring dialpad screen's vertical
diff --git a/res/values/strings.xml b/res/values/strings.xml
index fe0c5d6..a051173 100755
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -786,6 +786,9 @@
     <string name="card_title_my_phone_number">My number is <xliff:g id="my_phone_number">%s</xliff:g></string>
 
     <!-- Notification strings -->
+    <!-- The "label" of the in-call Notification for a dialing call, used
+         as the format string for a Chronometer widget. [CHAR LIMIT=60] -->
+    <string name="notification_dialing">Dialing</string>
     <!-- Missed call notification label, used when there's exactly one missed call -->
     <string name="notification_missedCallTitle">Missed call</string>
     <!-- Missed call notification label, used when there are two or more missed calls -->
diff --git a/res/values/styles.xml b/res/values/styles.xml
index 798cf07..28fb8f2 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -238,4 +238,18 @@
         <item name="android:editable">true</item>
         <item name="android:cursorVisible">false</item>
     </style>
+
+    <style name="PrimaryCallInfoPrimaryCallBanner">
+        <item name="android:layout_alignParentTop">true</item>
+    </style>
+    <style name="PrimaryCallInfoSecondaryInfoContainer">
+        <item name="android:layout_below">@id/primary_call_banner</item>
+    </style>
+
+    <style name="SecondaryCallInfoSecondaryCallName">
+        <item name="android:layout_gravity">top|left</item>
+    </style>
+    <style name="SecondaryCallInfoSecondaryCallStatus">
+        <item name="android:layout_gravity">top|right</item>
+    </style>
 </resources>
diff --git a/src/com/android/phone/BitmapUtils.java b/src/com/android/phone/BitmapUtils.java
index 0b8ba99..94d4bf9 100644
--- a/src/com/android/phone/BitmapUtils.java
+++ b/src/com/android/phone/BitmapUtils.java
@@ -28,7 +28,7 @@
 public class BitmapUtils {
     private static final String TAG = "BitmapUtils";
     private static final boolean DBG =
-            (PhoneApp.DBG_LEVEL >= 1) && (SystemProperties.getInt("ro.debuggable", 0) == 1);
+            (PhoneGlobals.DBG_LEVEL >= 1) && (SystemProperties.getInt("ro.debuggable", 0) == 1);
 
     /** This class is never instantiated. */
     private BitmapUtils() {
diff --git a/src/com/android/phone/BluetoothAtPhonebook.java b/src/com/android/phone/BluetoothAtPhonebook.java
deleted file mode 100644
index c9669c4..0000000
--- a/src/com/android/phone/BluetoothAtPhonebook.java
+++ /dev/null
@@ -1,529 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.phone;
-
-import com.android.internal.telephony.GsmAlphabet;
-
-import android.bluetooth.AtCommandHandler;
-import android.bluetooth.AtCommandResult;
-import android.bluetooth.AtParser;
-import android.bluetooth.BluetoothDevice;
-import android.bluetooth.HeadsetBase;
-import android.content.Context;
-import android.content.Intent;
-import android.database.Cursor;
-import android.net.Uri;
-import android.provider.CallLog.Calls;
-import android.provider.ContactsContract.CommonDataKinds.Phone;
-import android.provider.ContactsContract.PhoneLookup;
-import android.telephony.PhoneNumberUtils;
-import android.util.Log;
-
-import java.util.HashMap;
-
-/**
- * Helper for managing phonebook presentation over AT commands
- * @hide
- */
-public class BluetoothAtPhonebook {
-    private static final String TAG = "BluetoothAtPhonebook";
-    private static final boolean DBG = false;
-
-    /** The projection to use when querying the call log database in response
-     *  to AT+CPBR for the MC, RC, and DC phone books (missed, received, and
-     *   dialed calls respectively)
-     */
-    private static final String[] CALLS_PROJECTION = new String[] {
-        Calls._ID, Calls.NUMBER
-    };
-
-    /** The projection to use when querying the contacts database in response
-     *   to AT+CPBR for the ME phonebook (saved phone numbers).
-     */
-    private static final String[] PHONES_PROJECTION = new String[] {
-        Phone._ID, Phone.DISPLAY_NAME, Phone.NUMBER, Phone.TYPE
-    };
-
-    /** Android supports as many phonebook entries as the flash can hold, but
-     *  BT periphals don't. Limit the number we'll report. */
-    private static final int MAX_PHONEBOOK_SIZE = 16384;
-
-    private static final String OUTGOING_CALL_WHERE = Calls.TYPE + "=" + Calls.OUTGOING_TYPE;
-    private static final String INCOMING_CALL_WHERE = Calls.TYPE + "=" + Calls.INCOMING_TYPE;
-    private static final String MISSED_CALL_WHERE = Calls.TYPE + "=" + Calls.MISSED_TYPE;
-    private static final String VISIBLE_PHONEBOOK_WHERE = Phone.IN_VISIBLE_GROUP + "=1";
-
-    private class PhonebookResult {
-        public Cursor  cursor; // result set of last query
-        public int     numberColumn;
-        public int     typeColumn;
-        public int     nameColumn;
-    };
-
-    private final Context mContext;
-    private final BluetoothHandsfree mHandsfree;
-
-    private String mCurrentPhonebook;
-    private String mCharacterSet = "UTF-8";
-
-    private int mCpbrIndex1, mCpbrIndex2;
-    private boolean mCheckingAccessPermission;
-
-    // package and class name to which we send intent to check phone book access permission
-    private static final String ACCESS_AUTHORITY_PACKAGE = "com.android.settings";
-    private static final String ACCESS_AUTHORITY_CLASS =
-        "com.android.settings.bluetooth.BluetoothPermissionRequest";
-    private static final String BLUETOOTH_ADMIN_PERM = android.Manifest.permission.BLUETOOTH_ADMIN;
-
-    private final HashMap<String, PhonebookResult> mPhonebooks =
-            new HashMap<String, PhonebookResult>(4);
-
-    public BluetoothAtPhonebook(Context context, BluetoothHandsfree handsfree) {
-        mContext = context;
-        mHandsfree = handsfree;
-        mPhonebooks.put("DC", new PhonebookResult());  // dialled calls
-        mPhonebooks.put("RC", new PhonebookResult());  // received calls
-        mPhonebooks.put("MC", new PhonebookResult());  // missed calls
-        mPhonebooks.put("ME", new PhonebookResult());  // mobile phonebook
-
-        mCurrentPhonebook = "ME";  // default to mobile phonebook
-
-        mCpbrIndex1 = mCpbrIndex2 = -1;
-        mCheckingAccessPermission = false;
-    }
-
-    /** Returns the last dialled number, or null if no numbers have been called */
-    public String getLastDialledNumber() {
-        String[] projection = {Calls.NUMBER};
-        Cursor cursor = mContext.getContentResolver().query(Calls.CONTENT_URI, projection,
-                Calls.TYPE + "=" + Calls.OUTGOING_TYPE, null, Calls.DEFAULT_SORT_ORDER +
-                " LIMIT 1");
-        if (cursor == null) return null;
-
-        if (cursor.getCount() < 1) {
-            cursor.close();
-            return null;
-        }
-        cursor.moveToNext();
-        int column = cursor.getColumnIndexOrThrow(Calls.NUMBER);
-        String number = cursor.getString(column);
-        cursor.close();
-        return number;
-    }
-
-    public void register(AtParser parser) {
-        // Select Character Set
-        parser.register("+CSCS", new AtCommandHandler() {
-            @Override
-            public AtCommandResult handleReadCommand() {
-                String result = "+CSCS: \"" + mCharacterSet + "\"";
-                return new AtCommandResult(result);
-            }
-            @Override
-            public AtCommandResult handleSetCommand(Object[] args) {
-                if (args.length < 1) {
-                    return new AtCommandResult(AtCommandResult.ERROR);
-                }
-                String characterSet = (String)args[0];
-                characterSet = characterSet.replace("\"", "");
-                if (characterSet.equals("GSM") || characterSet.equals("IRA") ||
-                    characterSet.equals("UTF-8") || characterSet.equals("UTF8")) {
-                    mCharacterSet = characterSet;
-                    return new AtCommandResult(AtCommandResult.OK);
-                } else {
-                    return mHandsfree.reportCmeError(BluetoothCmeError.OPERATION_NOT_SUPPORTED);
-                }
-            }
-            @Override
-            public AtCommandResult handleTestCommand() {
-                return new AtCommandResult( "+CSCS: (\"UTF-8\",\"IRA\",\"GSM\")");
-            }
-        });
-
-        // Select PhoneBook memory Storage
-        parser.register("+CPBS", new AtCommandHandler() {
-            @Override
-            public AtCommandResult handleReadCommand() {
-                // Return current size and max size
-                if ("SM".equals(mCurrentPhonebook)) {
-                    return new AtCommandResult("+CPBS: \"SM\",0," + getMaxPhoneBookSize(0));
-                }
-
-                PhonebookResult pbr = getPhonebookResult(mCurrentPhonebook, true);
-                if (pbr == null) {
-                    return mHandsfree.reportCmeError(BluetoothCmeError.OPERATION_NOT_ALLOWED);
-                }
-                int size = pbr.cursor.getCount();
-                return new AtCommandResult("+CPBS: \"" + mCurrentPhonebook + "\"," +
-                        size + "," + getMaxPhoneBookSize(size));
-            }
-            @Override
-            public AtCommandResult handleSetCommand(Object[] args) {
-                // Select phonebook memory
-                if (args.length < 1 || !(args[0] instanceof String)) {
-                    return new AtCommandResult(AtCommandResult.ERROR);
-                }
-                String pb = ((String)args[0]).trim();
-                while (pb.endsWith("\"")) pb = pb.substring(0, pb.length() - 1);
-                while (pb.startsWith("\"")) pb = pb.substring(1, pb.length());
-                if (getPhonebookResult(pb, false) == null && !"SM".equals(pb)) {
-                    if (DBG) log("Dont know phonebook: '" + pb + "'");
-                    return mHandsfree.reportCmeError(BluetoothCmeError.OPERATION_NOT_SUPPORTED);
-                }
-                mCurrentPhonebook = pb;
-                return new AtCommandResult(AtCommandResult.OK);
-            }
-            @Override
-            public AtCommandResult handleTestCommand() {
-                return new AtCommandResult("+CPBS: (\"ME\",\"SM\",\"DC\",\"RC\",\"MC\")");
-            }
-        });
-
-        // Read PhoneBook Entries
-        parser.register("+CPBR", new AtCommandHandler() {
-            @Override
-            public AtCommandResult handleSetCommand(Object[] args) {
-                // Phone Book Read Request
-                // AT+CPBR=<index1>[,<index2>]
-
-                if (mCpbrIndex1 != -1) {
-                    /* handling a CPBR at the moment, reject this CPBR command */
-                    return mHandsfree.reportCmeError(BluetoothCmeError.OPERATION_NOT_ALLOWED);
-                }
-
-                // Parse indexes
-                int index1;
-                int index2;
-                if (args.length < 1 || !(args[0] instanceof Integer)) {
-                    return new AtCommandResult(AtCommandResult.ERROR);
-                } else {
-                    index1 = (Integer)args[0];
-                }
-
-                if (args.length == 1) {
-                    index2 = index1;
-                } else if (!(args[1] instanceof Integer)) {
-                    return mHandsfree.reportCmeError(BluetoothCmeError.TEXT_HAS_INVALID_CHARS);
-                } else {
-                    index2 = (Integer)args[1];
-                }
-
-                mCpbrIndex1 = index1;
-                mCpbrIndex2 = index2;
-                mCheckingAccessPermission = true;
-
-                if (checkAccessPermission()) {
-                    mCheckingAccessPermission = false;
-                    AtCommandResult atResult = processCpbrCommand();
-                    mCpbrIndex1 = mCpbrIndex2 = -1;
-                    return atResult;
-                }
-
-                // no reponse here, will continue the process in handleAccessPermissionResult
-                return new AtCommandResult(AtCommandResult.UNSOLICITED);
-            };
-
-            @Override
-            public AtCommandResult handleTestCommand() {
-                /* Ideally we should return the maximum range of valid index's
-                 * for the selected phone book, but this causes problems for the
-                 * Parrot CK3300. So instead send just the range of currently
-                 * valid index's.
-                 */
-                int size;
-                if ("SM".equals(mCurrentPhonebook)) {
-                    size = 0;
-                } else {
-                    PhonebookResult pbr = getPhonebookResult(mCurrentPhonebook, false);
-                    if (pbr == null) {
-                        return mHandsfree.reportCmeError(BluetoothCmeError.OPERATION_NOT_ALLOWED);
-                    }
-                    size = pbr.cursor.getCount();
-                }
-
-                if (size == 0) {
-                    /* Sending "+CPBR: (1-0)" can confused some carkits, send "1-1"
-                     * instead */
-                    size = 1;
-                }
-                return new AtCommandResult("+CPBR: (1-" + size + "),30,30");
-            }
-        });
-    }
-
-    /* package */ void handleAccessPermissionResult(Intent intent) {
-        if (!mCheckingAccessPermission) {
-            return;
-        }
-
-        HeadsetBase headset = mHandsfree.getHeadset();
-        // ASSERT: (headset != null) && headSet.isConnected()
-        // REASON: mCheckingAccessPermission is true, otherwise resetAtState
-        //         has set mCheckingAccessPermission to false
-
-        if (intent.getAction().equals(BluetoothDevice.ACTION_CONNECTION_ACCESS_REPLY)) {
-
-            if (intent.getIntExtra(BluetoothDevice.EXTRA_CONNECTION_ACCESS_RESULT,
-                                   BluetoothDevice.CONNECTION_ACCESS_NO) ==
-                BluetoothDevice.CONNECTION_ACCESS_YES) {
-                BluetoothDevice remoteDevice = headset.getRemoteDevice();
-                if (intent.getBooleanExtra(BluetoothDevice.EXTRA_ALWAYS_ALLOWED, false)) {
-                    remoteDevice.setTrust(true);
-                }
-
-                AtCommandResult cpbrResult = processCpbrCommand();
-                headset.sendURC(cpbrResult.toString());
-            } else {
-                headset.sendURC("ERROR");
-            }
-        }
-        mCpbrIndex1 = mCpbrIndex2 = -1;
-        mCheckingAccessPermission = false;
-    }
-
-    /** Get the most recent result for the given phone book,
-     *  with the cursor ready to go.
-     *  If force then re-query that phonebook
-     *  Returns null if the cursor is not ready
-     */
-    private synchronized PhonebookResult getPhonebookResult(String pb, boolean force) {
-        if (pb == null) {
-            return null;
-        }
-        PhonebookResult pbr = mPhonebooks.get(pb);
-        if (pbr == null) {
-            pbr = new PhonebookResult();
-        }
-        if (force || pbr.cursor == null) {
-            if (!queryPhonebook(pb, pbr)) {
-                return null;
-            }
-        }
-
-        return pbr;
-    }
-
-    private synchronized boolean queryPhonebook(String pb, PhonebookResult pbr) {
-        String where;
-        boolean ancillaryPhonebook = true;
-
-        if (pb.equals("ME")) {
-            ancillaryPhonebook = false;
-            where = VISIBLE_PHONEBOOK_WHERE;
-        } else if (pb.equals("DC")) {
-            where = OUTGOING_CALL_WHERE;
-        } else if (pb.equals("RC")) {
-            where = INCOMING_CALL_WHERE;
-        } else if (pb.equals("MC")) {
-            where = MISSED_CALL_WHERE;
-        } else {
-            return false;
-        }
-
-        if (pbr.cursor != null) {
-            pbr.cursor.close();
-            pbr.cursor = null;
-        }
-
-        if (ancillaryPhonebook) {
-            pbr.cursor = mContext.getContentResolver().query(
-                    Calls.CONTENT_URI, CALLS_PROJECTION, where, null,
-                    Calls.DEFAULT_SORT_ORDER + " LIMIT " + MAX_PHONEBOOK_SIZE);
-            if (pbr.cursor == null) return false;
-
-            pbr.numberColumn = pbr.cursor.getColumnIndexOrThrow(Calls.NUMBER);
-            pbr.typeColumn = -1;
-            pbr.nameColumn = -1;
-        } else {
-            pbr.cursor = mContext.getContentResolver().query(Phone.CONTENT_URI, PHONES_PROJECTION,
-                    where, null, Phone.NUMBER + " LIMIT " + MAX_PHONEBOOK_SIZE);
-            if (pbr.cursor == null) return false;
-
-            pbr.numberColumn = pbr.cursor.getColumnIndex(Phone.NUMBER);
-            pbr.typeColumn = pbr.cursor.getColumnIndex(Phone.TYPE);
-            pbr.nameColumn = pbr.cursor.getColumnIndex(Phone.DISPLAY_NAME);
-        }
-        Log.i(TAG, "Refreshed phonebook " + pb + " with " + pbr.cursor.getCount() + " results");
-        return true;
-    }
-
-    synchronized void resetAtState() {
-        mCharacterSet = "UTF-8";
-        mCpbrIndex1 = mCpbrIndex2 = -1;
-        mCheckingAccessPermission = false;
-    }
-
-    private synchronized int getMaxPhoneBookSize(int currSize) {
-        // some car kits ignore the current size and request max phone book
-        // size entries. Thus, it takes a long time to transfer all the
-        // entries. Use a heuristic to calculate the max phone book size
-        // considering future expansion.
-        // maxSize = currSize + currSize / 2 rounded up to nearest power of 2
-        // If currSize < 100, use 100 as the currSize
-
-        int maxSize = (currSize < 100) ? 100 : currSize;
-        maxSize += maxSize / 2;
-        return roundUpToPowerOfTwo(maxSize);
-    }
-
-    private int roundUpToPowerOfTwo(int x) {
-        x |= x >> 1;
-        x |= x >> 2;
-        x |= x >> 4;
-        x |= x >> 8;
-        x |= x >> 16;
-        return x + 1;
-    }
-
-    // process CPBR command after permission check
-    private AtCommandResult processCpbrCommand()
-    {
-        // Shortcut SM phonebook
-        if ("SM".equals(mCurrentPhonebook)) {
-            return new AtCommandResult(AtCommandResult.OK);
-        }
-
-        // Check phonebook
-        PhonebookResult pbr = getPhonebookResult(mCurrentPhonebook, false);
-        if (pbr == null) {
-            return mHandsfree.reportCmeError(BluetoothCmeError.OPERATION_NOT_ALLOWED);
-        }
-
-        // More sanity checks
-        // Send OK instead of ERROR if these checks fail.
-        // When we send error, certain kits like BMW disconnect the
-        // Handsfree connection.
-        if (pbr.cursor.getCount() == 0 || mCpbrIndex1 <= 0 || mCpbrIndex2 < mCpbrIndex1  ||
-            mCpbrIndex2 > pbr.cursor.getCount() || mCpbrIndex1 > pbr.cursor.getCount()) {
-            return new AtCommandResult(AtCommandResult.OK);
-        }
-
-        // Process
-        AtCommandResult result = new AtCommandResult(AtCommandResult.OK);
-        int errorDetected = -1; // no error
-        pbr.cursor.moveToPosition(mCpbrIndex1 - 1);
-        for (int index = mCpbrIndex1; index <= mCpbrIndex2; index++) {
-            String number = pbr.cursor.getString(pbr.numberColumn);
-            String name = null;
-            int type = -1;
-            if (pbr.nameColumn == -1) {
-                // try caller id lookup
-                // TODO: This code is horribly inefficient. I saw it
-                // take 7 seconds to process 100 missed calls.
-                Cursor c = mContext.getContentResolver().
-                    query(Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, number),
-                          new String[] {PhoneLookup.DISPLAY_NAME, PhoneLookup.TYPE},
-                          null, null, null);
-                if (c != null) {
-                    if (c.moveToFirst()) {
-                        name = c.getString(0);
-                        type = c.getInt(1);
-                    }
-                    c.close();
-                }
-                if (DBG && name == null) log("Caller ID lookup failed for " + number);
-
-            } else {
-                name = pbr.cursor.getString(pbr.nameColumn);
-            }
-            if (name == null) name = "";
-            name = name.trim();
-            if (name.length() > 28) name = name.substring(0, 28);
-
-            if (pbr.typeColumn != -1) {
-                type = pbr.cursor.getInt(pbr.typeColumn);
-                name = name + "/" + getPhoneType(type);
-            }
-
-            if (number == null) number = "";
-            int regionType = PhoneNumberUtils.toaFromString(number);
-
-            number = number.trim();
-            number = PhoneNumberUtils.stripSeparators(number);
-            if (number.length() > 30) number = number.substring(0, 30);
-            if (number.equals("-1")) {
-                // unknown numbers are stored as -1 in our database
-                number = "";
-                name = mContext.getString(R.string.unknown);
-            }
-
-            // TODO(): Handle IRA commands. It's basically
-            // a 7 bit ASCII character set.
-            if (!name.equals("") && mCharacterSet.equals("GSM")) {
-                byte[] nameByte = GsmAlphabet.stringToGsm8BitPacked(name);
-                if (nameByte == null) {
-                    name = mContext.getString(R.string.unknown);
-                } else {
-                    name = new String(nameByte);
-                }
-            }
-
-            result.addResponse("+CPBR: " + index + ",\"" + number + "\"," +
-                               regionType + ",\"" + name + "\"");
-            if (!pbr.cursor.moveToNext()) {
-                break;
-            }
-        }
-        return result;
-    }
-
-    // Check if the remote device has premission to read our phone book
-    // Return true if it has the permission
-    //        false if not known and we have sent our Intent to check
-    private boolean checkAccessPermission() {
-        BluetoothDevice remoteDevice = mHandsfree.getHeadset().getRemoteDevice();
-
-        boolean trust = remoteDevice.getTrustState();
-
-        if (trust) {
-            return true;
-        }
-
-        Intent intent = new Intent(BluetoothDevice.ACTION_CONNECTION_ACCESS_REQUEST);
-        intent.setClassName(ACCESS_AUTHORITY_PACKAGE, ACCESS_AUTHORITY_CLASS);
-        intent.putExtra(BluetoothDevice.EXTRA_ACCESS_REQUEST_TYPE,
-                        BluetoothDevice.REQUEST_TYPE_PHONEBOOK_ACCESS);
-        intent.putExtra(BluetoothDevice.EXTRA_DEVICE, remoteDevice);
-        // Leave EXTRA_PACKAGE_NAME and EXTRA_CLASS_NAME field empty
-        // BluetoothHandsfree's broadcast receiver is anonymous, cannot be targeted
-        mContext.sendBroadcast(intent, BLUETOOTH_ADMIN_PERM);
-
-        return false;
-    }
-
-    private static String getPhoneType(int type) {
-        switch (type) {
-            case Phone.TYPE_HOME:
-                return "H";
-            case Phone.TYPE_MOBILE:
-                return "M";
-            case Phone.TYPE_WORK:
-                return "W";
-            case Phone.TYPE_FAX_HOME:
-            case Phone.TYPE_FAX_WORK:
-                return "F";
-            case Phone.TYPE_OTHER:
-            case Phone.TYPE_CUSTOM:
-            default:
-                return "O";
-        }
-    }
-
-    private static void log(String msg) {
-        Log.d(TAG, msg);
-    }
-}
diff --git a/src/com/android/phone/BluetoothCmeError.java b/src/com/android/phone/BluetoothCmeError.java
deleted file mode 100644
index aa5e887..0000000
--- a/src/com/android/phone/BluetoothCmeError.java
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.phone;
-
-/* Constants for extended AT error codes specified by the Handsfree profile. */
-public class BluetoothCmeError {
-    public static final int AG_FAILURE = 0;
-    public static final int NO_CONNECTION_TO_PHONE = 1;
-    public static final int OPERATION_NOT_ALLOWED = 3;
-    public static final int OPERATION_NOT_SUPPORTED = 4;
-    public static final int PIN_REQUIRED = 5;
-    public static final int SIM_MISSING = 10;
-    public static final int SIM_PIN_REQUIRED = 11;
-    public static final int SIM_PUK_REQUIRED = 12;
-    public static final int SIM_FAILURE = 13;
-    public static final int SIM_BUSY = 14;
-    public static final int WRONG_PASSWORD = 16;
-    public static final int SIM_PIN2_REQUIRED = 17;
-    public static final int SIM_PUK2_REQUIRED = 18;
-    public static final int MEMORY_FULL = 20;
-    public static final int INVALID_INDEX = 21;
-    public static final int MEMORY_FAILURE = 23;
-    public static final int TEXT_TOO_LONG = 24;
-    public static final int TEXT_HAS_INVALID_CHARS = 25;
-    public static final int DIAL_STRING_TOO_LONG = 26;
-    public static final int DIAL_STRING_HAS_INVALID_CHARS = 27;
-    public static final int NO_SERVICE = 30;
-    public static final int ONLY_911_ALLOWED = 32;
-}
diff --git a/src/com/android/phone/BluetoothHandsfree.java b/src/com/android/phone/BluetoothHandsfree.java
deleted file mode 100755
index 5845397..0000000
--- a/src/com/android/phone/BluetoothHandsfree.java
+++ /dev/null
@@ -1,3071 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.phone;
-
-import android.bluetooth.AtCommandHandler;
-import android.bluetooth.AtCommandResult;
-import android.bluetooth.AtParser;
-import android.bluetooth.BluetoothA2dp;
-import android.bluetooth.BluetoothAssignedNumbers;
-import android.bluetooth.BluetoothAdapter;
-import android.bluetooth.BluetoothDevice;
-import android.bluetooth.BluetoothHeadset;
-import android.bluetooth.BluetoothProfile;
-import android.bluetooth.BluetoothServerSocket;
-import android.bluetooth.BluetoothSocket;
-import android.bluetooth.HeadsetBase;
-import android.content.ActivityNotFoundException;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.media.AudioManager;
-import android.net.Uri;
-import android.os.AsyncResult;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.HandlerThread;
-import android.os.Looper;
-import android.os.Message;
-import android.os.PowerManager;
-import android.os.PowerManager.WakeLock;
-import android.os.SystemProperties;
-import android.telephony.PhoneNumberUtils;
-import android.telephony.ServiceState;
-import android.telephony.SignalStrength;
-import android.telephony.TelephonyManager;
-import android.util.Log;
-
-import com.android.internal.telephony.Call;
-import com.android.internal.telephony.Connection;
-import com.android.internal.telephony.Phone;
-import com.android.internal.telephony.PhoneConstants;
-import com.android.internal.telephony.TelephonyIntents;
-import com.android.internal.telephony.CallManager;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.LinkedList;
-
-/**
- * Bluetooth headset manager for the Phone app.
- * @hide
- */
-public class BluetoothHandsfree {
-    private static final String TAG = "Bluetooth HS/HF";
-    private static final boolean DBG = (PhoneApp.DBG_LEVEL >= 1)
-            && (SystemProperties.getInt("ro.debuggable", 0) == 1);
-    private static final boolean VDBG = (PhoneApp.DBG_LEVEL >= 2);  // even more logging
-
-    public static final int TYPE_UNKNOWN           = 0;
-    public static final int TYPE_HEADSET           = 1;
-    public static final int TYPE_HANDSFREE         = 2;
-
-    /** The singleton instance. */
-    private static BluetoothHandsfree sInstance;
-
-    private final Context mContext;
-    private final BluetoothAdapter mAdapter;
-    private final CallManager mCM;
-    private BluetoothA2dp mA2dp;
-
-    private BluetoothDevice mA2dpDevice;
-    private int mA2dpState;
-    private boolean mPendingAudioState;
-    private int mAudioState;
-
-    private ServiceState mServiceState;
-    private HeadsetBase mHeadset;
-    private BluetoothHeadset mBluetoothHeadset;
-    private int mHeadsetType;   // TYPE_UNKNOWN when not connected
-    private boolean mAudioPossible;
-    private BluetoothSocket mConnectedSco;
-
-    private IncomingScoAcceptThread mIncomingScoThread = null;
-    private ScoSocketConnectThread mConnectScoThread = null;
-    private SignalScoCloseThread mSignalScoCloseThread = null;
-
-    private AudioManager mAudioManager;
-    private PowerManager mPowerManager;
-
-    private boolean mPendingSco;  // waiting for a2dp sink to suspend before establishing SCO
-    private boolean mA2dpSuspended;
-    private boolean mUserWantsAudio;
-    private WakeLock mStartCallWakeLock;  // held while waiting for the intent to start call
-    private WakeLock mStartVoiceRecognitionWakeLock;  // held while waiting for voice recognition
-
-    // AT command state
-    private static final int GSM_MAX_CONNECTIONS = 6;  // Max connections allowed by GSM
-    private static final int CDMA_MAX_CONNECTIONS = 2;  // Max connections allowed by CDMA
-
-    private long mBgndEarliestConnectionTime = 0;
-    private boolean mClip = false;  // Calling Line Information Presentation
-    private boolean mIndicatorsEnabled = false;
-    private boolean mCmee = false;  // Extended Error reporting
-    private long[] mClccTimestamps; // Timestamps associated with each clcc index
-    private boolean[] mClccUsed;     // Is this clcc index in use
-    private boolean mWaitingForCallStart;
-    private boolean mWaitingForVoiceRecognition;
-    // do not connect audio until service connection is established
-    // for 3-way supported devices, this is after AT+CHLD
-    // for non-3-way supported devices, this is after AT+CMER (see spec)
-    private boolean mServiceConnectionEstablished;
-
-    private final BluetoothPhoneState mBluetoothPhoneState;  // for CIND and CIEV updates
-    private final BluetoothAtPhonebook mPhonebook;
-    private PhoneConstants.State mPhoneState = PhoneConstants.State.IDLE;
-    CdmaPhoneCallState.PhoneCallState mCdmaThreeWayCallState =
-                                            CdmaPhoneCallState.PhoneCallState.IDLE;
-
-    private DebugThread mDebugThread;
-    private int mScoGain = Integer.MIN_VALUE;
-
-    private static Intent sVoiceCommandIntent;
-
-    // Audio parameters
-    private static final String HEADSET_NREC = "bt_headset_nrec";
-    private static final String HEADSET_NAME = "bt_headset_name";
-
-    private int mRemoteBrsf = 0;
-    private int mLocalBrsf = 0;
-
-    // CDMA specific flag used in context with BT devices having display capabilities
-    // to show which Caller is active. This state might not be always true as in CDMA
-    // networks if a caller drops off no update is provided to the Phone.
-    // This flag is just used as a toggle to provide a update to the BT device to specify
-    // which caller is active.
-    private boolean mCdmaIsSecondCallActive = false;
-    private boolean mCdmaCallsSwapped = false;
-
-    /* Constants from Bluetooth Specification Hands-Free profile version 1.5 */
-    private static final int BRSF_AG_THREE_WAY_CALLING = 1 << 0;
-    private static final int BRSF_AG_EC_NR = 1 << 1;
-    private static final int BRSF_AG_VOICE_RECOG = 1 << 2;
-    private static final int BRSF_AG_IN_BAND_RING = 1 << 3;
-    private static final int BRSF_AG_VOICE_TAG_NUMBE = 1 << 4;
-    private static final int BRSF_AG_REJECT_CALL = 1 << 5;
-    private static final int BRSF_AG_ENHANCED_CALL_STATUS = 1 <<  6;
-    private static final int BRSF_AG_ENHANCED_CALL_CONTROL = 1 << 7;
-    private static final int BRSF_AG_ENHANCED_ERR_RESULT_CODES = 1 << 8;
-
-    private static final int BRSF_HF_EC_NR = 1 << 0;
-    private static final int BRSF_HF_CW_THREE_WAY_CALLING = 1 << 1;
-    private static final int BRSF_HF_CLIP = 1 << 2;
-    private static final int BRSF_HF_VOICE_REG_ACT = 1 << 3;
-    private static final int BRSF_HF_REMOTE_VOL_CONTROL = 1 << 4;
-    private static final int BRSF_HF_ENHANCED_CALL_STATUS = 1 <<  5;
-    private static final int BRSF_HF_ENHANCED_CALL_CONTROL = 1 << 6;
-
-    // VirtualCall - true if Virtual Call is active, false otherwise
-    private boolean mVirtualCallStarted = false;
-
-    // Voice Recognition - true if Voice Recognition is active, false otherwise
-    private boolean mVoiceRecognitionStarted;
-
-    private HandsfreeMessageHandler mHandler;
-
-    public static String typeToString(int type) {
-        switch (type) {
-        case TYPE_UNKNOWN:
-            return "unknown";
-        case TYPE_HEADSET:
-            return "headset";
-        case TYPE_HANDSFREE:
-            return "handsfree";
-        }
-        return null;
-    }
-
-    /**
-     * Initialize the singleton BluetoothHandsfree instance.
-     * This is only done once, at startup, from PhoneApp.onCreate().
-     */
-    /* package */ static BluetoothHandsfree init(Context context, CallManager cm) {
-        synchronized (BluetoothHandsfree.class) {
-            if (sInstance == null) {
-                sInstance = new BluetoothHandsfree(context, cm);
-            } else {
-                Log.wtf(TAG, "init() called multiple times!  sInstance = " + sInstance);
-            }
-            return sInstance;
-        }
-    }
-
-    /** Private constructor; @see init() */
-    private BluetoothHandsfree(Context context, CallManager cm) {
-        mCM = cm;
-        mContext = context;
-        mAdapter = BluetoothAdapter.getDefaultAdapter();
-        boolean bluetoothCapable = (mAdapter != null);
-        mHeadset = null;
-        mHeadsetType = TYPE_UNKNOWN; // nothing connected yet
-        if (bluetoothCapable) {
-            mAdapter.getProfileProxy(mContext, mProfileListener,
-                                     BluetoothProfile.A2DP);
-        }
-        mA2dpState = BluetoothA2dp.STATE_DISCONNECTED;
-        mA2dpDevice = null;
-        mA2dpSuspended = false;
-
-        mPowerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
-        mStartCallWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
-                                                       TAG + ":StartCall");
-        mStartCallWakeLock.setReferenceCounted(false);
-        mStartVoiceRecognitionWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
-                                                       TAG + ":VoiceRecognition");
-        mStartVoiceRecognitionWakeLock.setReferenceCounted(false);
-
-        mLocalBrsf = BRSF_AG_THREE_WAY_CALLING |
-                     BRSF_AG_EC_NR |
-                     BRSF_AG_REJECT_CALL |
-                     BRSF_AG_ENHANCED_CALL_STATUS;
-
-        if (sVoiceCommandIntent == null) {
-            sVoiceCommandIntent = new Intent(Intent.ACTION_VOICE_COMMAND);
-            sVoiceCommandIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-        }
-        if (mContext.getPackageManager().resolveActivity(sVoiceCommandIntent, 0) != null &&
-                BluetoothHeadset.isBluetoothVoiceDialingEnabled(mContext)) {
-            mLocalBrsf |= BRSF_AG_VOICE_RECOG;
-        }
-
-        HandlerThread thread = new HandlerThread("BluetoothHandsfreeHandler");
-        thread.start();
-        Looper looper = thread.getLooper();
-        mHandler = new HandsfreeMessageHandler(looper);
-        mBluetoothPhoneState = new BluetoothPhoneState();
-        mUserWantsAudio = true;
-        mVirtualCallStarted = false;
-        mVoiceRecognitionStarted = false;
-        mPhonebook = new BluetoothAtPhonebook(mContext, this);
-        mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
-        cdmaSetSecondCallState(false);
-
-        if (bluetoothCapable) {
-            resetAtState();
-        }
-
-    }
-
-    /**
-     * A thread that runs in the background waiting for a Sco Server Socket to
-     * accept a connection. Even after a connection has been accepted, the Sco Server
-     * continues to listen for new connections.
-     */
-    private class IncomingScoAcceptThread extends Thread{
-        private final BluetoothServerSocket mIncomingServerSocket;
-        private BluetoothSocket mIncomingSco;
-        private boolean stopped = false;
-
-        public IncomingScoAcceptThread() {
-            BluetoothServerSocket serverSocket = null;
-            try {
-                serverSocket = BluetoothAdapter.listenUsingScoOn();
-            } catch (IOException e) {
-                Log.e(TAG, "Could not create BluetoothServerSocket");
-                stopped = true;
-            }
-            mIncomingServerSocket = serverSocket;
-        }
-
-        @Override
-        public void run() {
-            while (!stopped) {
-                try {
-                    mIncomingSco = mIncomingServerSocket.accept();
-                } catch (IOException e) {
-                    Log.e(TAG, "BluetoothServerSocket could not accept connection");
-                }
-
-                if (mIncomingSco != null) {
-                    connectSco();
-                }
-            }
-        }
-
-        private void connectSco() {
-            synchronized (BluetoothHandsfree.this) {
-                if (!Thread.interrupted() && isHeadsetConnected() &&
-                    (mAudioPossible || allowAudioAnytime()) &&
-                    mConnectedSco == null) {
-                    Log.i(TAG, "Routing audio for incoming SCO connection");
-                    mConnectedSco = mIncomingSco;
-                    mAudioManager.setBluetoothScoOn(true);
-                    setAudioState(BluetoothHeadset.STATE_AUDIO_CONNECTED,
-                        mHeadset.getRemoteDevice());
-
-                    if (mSignalScoCloseThread == null) {
-                        mSignalScoCloseThread = new SignalScoCloseThread();
-                        mSignalScoCloseThread.setName("SignalScoCloseThread");
-                        mSignalScoCloseThread.start();
-                    }
-                } else {
-                    Log.i(TAG, "Rejecting incoming SCO connection");
-                    try {
-                        mIncomingSco.close();
-                    }catch (IOException e) {
-                        Log.e(TAG, "Error when closing incoming Sco socket");
-                    }
-                    mIncomingSco = null;
-                }
-            }
-        }
-
-        // must be called with BluetoothHandsfree locked
-        void shutdown() {
-            try {
-                mIncomingServerSocket.close();
-            } catch (IOException e) {
-                Log.w(TAG, "Error when closing server socket");
-            }
-            stopped = true;
-            interrupt();
-        }
-    }
-
-    /**
-     * A thread that runs in the background waiting for a Sco Socket to
-     * connect.Once the socket is connected, this thread shall be
-     * shutdown.
-     */
-    private class ScoSocketConnectThread extends Thread{
-        private BluetoothSocket mOutgoingSco;
-
-        public ScoSocketConnectThread(BluetoothDevice device) {
-            try {
-                mOutgoingSco = device.createScoSocket();
-            } catch (IOException e) {
-                Log.w(TAG, "Could not create BluetoothSocket");
-                failedScoConnect();
-            }
-        }
-
-        @Override
-        public void run() {
-            try {
-                mOutgoingSco.connect();
-            }catch (IOException connectException) {
-                Log.e(TAG, "BluetoothSocket could not connect");
-                mOutgoingSco = null;
-                failedScoConnect();
-            }
-
-            if (mOutgoingSco != null) {
-                connectSco();
-            }
-        }
-
-        private void connectSco() {
-            synchronized (BluetoothHandsfree.this) {
-                if (!Thread.interrupted() && isHeadsetConnected() && mConnectedSco == null) {
-                    if (VDBG) log("Routing audio for outgoing SCO conection");
-                    mConnectedSco = mOutgoingSco;
-                    mAudioManager.setBluetoothScoOn(true);
-
-                    setAudioState(BluetoothHeadset.STATE_AUDIO_CONNECTED,
-                      mHeadset.getRemoteDevice());
-
-                    if (mSignalScoCloseThread == null) {
-                        mSignalScoCloseThread = new SignalScoCloseThread();
-                        mSignalScoCloseThread.setName("SignalScoCloseThread");
-                        mSignalScoCloseThread.start();
-                    }
-                } else {
-                    if (VDBG) log("Rejecting new connected outgoing SCO socket");
-                    try {
-                        mOutgoingSco.close();
-                    }catch (IOException e) {
-                        Log.e(TAG, "Error when closing Sco socket");
-                    }
-                    mOutgoingSco = null;
-                    failedScoConnect();
-                }
-            }
-        }
-
-        private void failedScoConnect() {
-            // Wait for couple of secs before sending AUDIO_STATE_DISCONNECTED,
-            // since an incoming SCO connection can happen immediately with
-            // certain headsets.
-            Message msg = Message.obtain(mHandler, SCO_AUDIO_STATE);
-            msg.obj = mHeadset.getRemoteDevice();
-            mHandler.sendMessageDelayed(msg, 2000);
-
-            // Sync with interrupt() statement of shutdown method
-            // This prevents resetting of a valid mConnectScoThread.
-            // If this thread has been interrupted, it has been shutdown and
-            // mConnectScoThread is/will be reset by the outer class.
-            // We do not want to do it here since mConnectScoThread could be
-            // assigned with a new object.
-            synchronized (ScoSocketConnectThread.this) {
-                if (!isInterrupted()) {
-                    resetConnectScoThread();
-                }
-            }
-        }
-
-        // must be called with BluetoothHandsfree locked
-        void shutdown() {
-            closeConnectedSco();
-
-            // sync with isInterrupted() check in failedScoConnect method
-            // see explanation there
-            synchronized (ScoSocketConnectThread.this) {
-                interrupt();
-            }
-        }
-    }
-
-    /*
-     * Signals when a Sco connection has been closed
-     */
-    private class SignalScoCloseThread extends Thread{
-        private boolean stopped = false;
-
-        @Override
-        public void run() {
-            while (!stopped) {
-                BluetoothSocket connectedSco = null;
-                synchronized (BluetoothHandsfree.this) {
-                    connectedSco = mConnectedSco;
-                }
-                if (connectedSco != null) {
-                    byte b[] = new byte[1];
-                    InputStream inStream = null;
-                    try {
-                        inStream = connectedSco.getInputStream();
-                    } catch (IOException e) {}
-
-                    if (inStream != null) {
-                        try {
-                            // inStream.read is a blocking call that won't ever
-                            // return anything, but will throw an exception if the
-                            // connection is closed
-                            int ret = inStream.read(b, 0, 1);
-                        }catch (IOException connectException) {
-                            // call a message to close this thread and turn off audio
-                            // we can't call audioOff directly because then
-                            // the thread would try to close itself
-                            Message msg = Message.obtain(mHandler, SCO_CLOSED);
-                            mHandler.sendMessage(msg);
-                            break;
-                        }
-                    }
-                }
-            }
-        }
-
-        // must be called with BluetoothHandsfree locked
-        void shutdown() {
-            stopped = true;
-            closeConnectedSco();
-            interrupt();
-        }
-    }
-
-    private void connectScoThread(){
-        // Sync with setting mConnectScoThread to null to assure the validity of
-        // the condition
-        synchronized (ScoSocketConnectThread.class) {
-            if (mConnectScoThread == null) {
-                BluetoothDevice device = mHeadset.getRemoteDevice();
-                if (getAudioState(device) == BluetoothHeadset.STATE_AUDIO_DISCONNECTED) {
-                    setAudioState(BluetoothHeadset.STATE_AUDIO_CONNECTING, device);
-                }
-
-                mConnectScoThread = new ScoSocketConnectThread(mHeadset.getRemoteDevice());
-                mConnectScoThread.setName("HandsfreeScoSocketConnectThread");
-
-                mConnectScoThread.start();
-            }
-        }
-    }
-
-    private void resetConnectScoThread() {
-        // Sync with if (mConnectScoThread == null) check
-        synchronized (ScoSocketConnectThread.class) {
-            mConnectScoThread = null;
-        }
-    }
-
-    // must be called with BluetoothHandsfree locked
-    private void closeConnectedSco() {
-        if (mConnectedSco != null) {
-            try {
-                mConnectedSco.close();
-            } catch (IOException e) {
-                Log.e(TAG, "Error when closing Sco socket");
-            }
-
-            BluetoothDevice device = null;
-            if (mHeadset != null) {
-                device = mHeadset.getRemoteDevice();
-            }
-            mAudioManager.setBluetoothScoOn(false);
-            setAudioState(BluetoothHeadset.STATE_AUDIO_DISCONNECTED, device);
-
-            mConnectedSco = null;
-        }
-    }
-
-    /* package */ synchronized void onBluetoothEnabled() {
-        /* Bluez has a bug where it will always accept and then orphan
-         * incoming SCO connections, regardless of whether we have a listening
-         * SCO socket. So the best thing to do is always run a listening socket
-         * while bluetooth is on so that at least we can disconnect it
-         * immediately when we don't want it.
-         */
-
-        if (mIncomingScoThread == null) {
-            mIncomingScoThread = new IncomingScoAcceptThread();
-            mIncomingScoThread.setName("incomingScoAcceptThread");
-            mIncomingScoThread.start();
-        }
-    }
-
-    /* package */ synchronized void onBluetoothDisabled() {
-        // Close off the SCO sockets
-        audioOff();
-
-        if (mIncomingScoThread != null) {
-            mIncomingScoThread.shutdown();
-            mIncomingScoThread = null;
-        }
-    }
-
-    private boolean isHeadsetConnected() {
-        if (mHeadset == null || mHeadsetType == TYPE_UNKNOWN) {
-            return false;
-        }
-        return mHeadset.isConnected();
-    }
-
-    /* package */ synchronized void connectHeadset(HeadsetBase headset, int headsetType) {
-        mHeadset = headset;
-        mHeadsetType = headsetType;
-        if (mHeadsetType == TYPE_HEADSET) {
-            initializeHeadsetAtParser();
-        } else {
-            initializeHandsfreeAtParser();
-        }
-
-        // Headset vendor-specific commands
-        registerAllVendorSpecificCommands();
-
-        headset.startEventThread();
-        configAudioParameters();
-
-        if (inDebug()) {
-            startDebug();
-        }
-
-        if (isIncallAudio()) {
-            audioOn();
-        } else if ( mCM.getFirstActiveRingingCall().isRinging()) {
-            // need to update HS with RING when single ringing call exist
-            mBluetoothPhoneState.ring();
-        }
-    }
-
-    /* returns true if there is some kind of in-call audio we may wish to route
-     * bluetooth to */
-    private boolean isIncallAudio() {
-        Call.State state = mCM.getActiveFgCallState();
-
-        return (state == Call.State.ACTIVE || state == Call.State.ALERTING);
-    }
-
-    /* package */ synchronized void disconnectHeadset() {
-        audioOff();
-
-        // No need to check if isVirtualCallInProgress()
-        // terminateScoUsingVirtualVoiceCall() does the check
-        terminateScoUsingVirtualVoiceCall();
-
-        mHeadsetType = TYPE_UNKNOWN;
-        stopDebug();
-        resetAtState();
-    }
-
-    /* package */ synchronized void resetAtState() {
-        mClip = false;
-        mIndicatorsEnabled = false;
-        mServiceConnectionEstablished = false;
-        mCmee = false;
-        mClccTimestamps = new long[GSM_MAX_CONNECTIONS];
-        mClccUsed = new boolean[GSM_MAX_CONNECTIONS];
-        for (int i = 0; i < GSM_MAX_CONNECTIONS; i++) {
-            mClccUsed[i] = false;
-        }
-        mRemoteBrsf = 0;
-        mPhonebook.resetAtState();
-    }
-
-    /* package */ HeadsetBase getHeadset() {
-        return mHeadset;
-    }
-
-    private void configAudioParameters() {
-        String name = mHeadset.getRemoteDevice().getName();
-        if (name == null) {
-            name = "<unknown>";
-        }
-        mAudioManager.setParameters(HEADSET_NAME+"="+name+";"+HEADSET_NREC+"=on");
-    }
-
-
-    /** Represents the data that we send in a +CIND or +CIEV command to the HF
-     */
-    private class BluetoothPhoneState {
-        // 0: no service
-        // 1: service
-        private int mService;
-
-        // 0: no active call
-        // 1: active call (where active means audio is routed - not held call)
-        private int mCall;
-
-        // 0: not in call setup
-        // 1: incoming call setup
-        // 2: outgoing call setup
-        // 3: remote party being alerted in an outgoing call setup
-        private int mCallsetup;
-
-        // 0: no calls held
-        // 1: held call and active call
-        // 2: held call only
-        private int mCallheld;
-
-        // cellular signal strength of AG: 0-5
-        private int mSignal;
-
-        // cellular signal strength in CSQ rssi scale
-        private int mRssi;  // for CSQ
-
-        // 0: roaming not active (home)
-        // 1: roaming active
-        private int mRoam;
-
-        // battery charge of AG: 0-5
-        private int mBattchg;
-
-        // 0: not registered
-        // 1: registered, home network
-        // 5: registered, roaming
-        private int mStat;  // for CREG
-
-        private String mRingingNumber;  // Context for in-progress RING's
-        private int    mRingingType;
-        private boolean mIgnoreRing = false;
-        private boolean mStopRing = false;
-
-        // current or last call start timestamp
-        private long mCallStartTime = 0;
-        // time window to reconnect remotely-disconnected SCO
-        // in mili-seconds
-        private static final int RETRY_SCO_TIME_WINDOW = 1000;
-
-        private static final int SERVICE_STATE_CHANGED = 1;
-        private static final int PRECISE_CALL_STATE_CHANGED = 2;
-        private static final int RING = 3;
-        private static final int PHONE_CDMA_CALL_WAITING = 4;
-
-        private Handler mStateChangeHandler = new Handler() {
-            @Override
-            public void handleMessage(Message msg) {
-                switch(msg.what) {
-                case RING:
-                    AtCommandResult result = ring();
-                    if (result != null) {
-                        sendURC(result.toString());
-                    }
-                    break;
-                case SERVICE_STATE_CHANGED:
-                    ServiceState state = (ServiceState) ((AsyncResult) msg.obj).result;
-                    updateServiceState(sendUpdate(), state);
-                    break;
-                case PRECISE_CALL_STATE_CHANGED:
-                case PHONE_CDMA_CALL_WAITING:
-                    Connection connection = null;
-                    if (((AsyncResult) msg.obj).result instanceof Connection) {
-                        connection = (Connection) ((AsyncResult) msg.obj).result;
-                    }
-                    handlePreciseCallStateChange(sendUpdate(), connection);
-                    break;
-                }
-            }
-        };
-
-        private BluetoothPhoneState() {
-            // init members
-            // TODO May consider to repalce the default phone's state and signal
-            //      by CallManagter's state and signal
-            updateServiceState(false, mCM.getDefaultPhone().getServiceState());
-            handlePreciseCallStateChange(false, null);
-            mBattchg = 5;  // There is currently no API to get battery level
-                           // on demand, so set to 5 and wait for an update
-            mSignal = asuToSignal(mCM.getDefaultPhone().getSignalStrength());
-
-            // register for updates
-            // Use the service state of default phone as BT service state to
-            // avoid situation such as no cell or wifi connection but still
-            // reporting in service (since SipPhone always reports in service).
-            mCM.getDefaultPhone().registerForServiceStateChanged(mStateChangeHandler,
-                                                  SERVICE_STATE_CHANGED, null);
-            mCM.registerForPreciseCallStateChanged(mStateChangeHandler,
-                    PRECISE_CALL_STATE_CHANGED, null);
-            mCM.registerForCallWaiting(mStateChangeHandler,
-                PHONE_CDMA_CALL_WAITING, null);
-
-            IntentFilter filter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
-            filter.addAction(TelephonyIntents.ACTION_SIGNAL_STRENGTH_CHANGED);
-            filter.addAction(BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED);
-            filter.addAction(BluetoothDevice.ACTION_CONNECTION_ACCESS_REPLY);
-            mContext.registerReceiver(mStateReceiver, filter);
-        }
-
-        private void updateBtPhoneStateAfterRadioTechnologyChange() {
-            if(VDBG) Log.d(TAG, "updateBtPhoneStateAfterRadioTechnologyChange...");
-
-            //Unregister all events from the old obsolete phone
-            mCM.getDefaultPhone().unregisterForServiceStateChanged(mStateChangeHandler);
-            mCM.unregisterForPreciseCallStateChanged(mStateChangeHandler);
-            mCM.unregisterForCallWaiting(mStateChangeHandler);
-
-            //Register all events new to the new active phone
-            mCM.getDefaultPhone().registerForServiceStateChanged(mStateChangeHandler,
-                                                  SERVICE_STATE_CHANGED, null);
-            mCM.registerForPreciseCallStateChanged(mStateChangeHandler,
-                    PRECISE_CALL_STATE_CHANGED, null);
-            mCM.registerForCallWaiting(mStateChangeHandler,
-                PHONE_CDMA_CALL_WAITING, null);
-        }
-
-        private boolean sendUpdate() {
-            return isHeadsetConnected() && mHeadsetType == TYPE_HANDSFREE && mIndicatorsEnabled
-                   && mServiceConnectionEstablished;
-        }
-
-        private boolean sendClipUpdate() {
-            return isHeadsetConnected() && mHeadsetType == TYPE_HANDSFREE && mClip &&
-                   mServiceConnectionEstablished;
-        }
-
-        private boolean sendRingUpdate() {
-            if (isHeadsetConnected() && !mIgnoreRing && !mStopRing &&
-                    mCM.getFirstActiveRingingCall().isRinging()) {
-                if (mHeadsetType == TYPE_HANDSFREE) {
-                    return mServiceConnectionEstablished ? true : false;
-                }
-                return true;
-            }
-            return false;
-        }
-
-        private void stopRing() {
-            mStopRing = true;
-        }
-
-        /* convert [0,31] ASU signal strength to the [0,5] expected by
-         * bluetooth devices. Scale is similar to status bar policy
-         */
-        private int gsmAsuToSignal(SignalStrength signalStrength) {
-            int asu = signalStrength.getGsmSignalStrength();
-            if      (asu >= 16) return 5;
-            else if (asu >= 8)  return 4;
-            else if (asu >= 4)  return 3;
-            else if (asu >= 2)  return 2;
-            else if (asu >= 1)  return 1;
-            else                return 0;
-        }
-
-        /**
-         * Convert the cdma / evdo db levels to appropriate icon level.
-         * The scale is similar to the one used in status bar policy.
-         *
-         * @param signalStrength
-         * @return the icon level
-         */
-        private int cdmaDbmEcioToSignal(SignalStrength signalStrength) {
-            int levelDbm = 0;
-            int levelEcio = 0;
-            int cdmaIconLevel = 0;
-            int evdoIconLevel = 0;
-            int cdmaDbm = signalStrength.getCdmaDbm();
-            int cdmaEcio = signalStrength.getCdmaEcio();
-
-            if (cdmaDbm >= -75) levelDbm = 4;
-            else if (cdmaDbm >= -85) levelDbm = 3;
-            else if (cdmaDbm >= -95) levelDbm = 2;
-            else if (cdmaDbm >= -100) levelDbm = 1;
-            else levelDbm = 0;
-
-            // Ec/Io are in dB*10
-            if (cdmaEcio >= -90) levelEcio = 4;
-            else if (cdmaEcio >= -110) levelEcio = 3;
-            else if (cdmaEcio >= -130) levelEcio = 2;
-            else if (cdmaEcio >= -150) levelEcio = 1;
-            else levelEcio = 0;
-
-            cdmaIconLevel = (levelDbm < levelEcio) ? levelDbm : levelEcio;
-
-            if (mServiceState != null &&
-                  (mServiceState.getNetworkType() == TelephonyManager.NETWORK_TYPE_EVDO_0 ||
-                   mServiceState.getNetworkType() == TelephonyManager.NETWORK_TYPE_EVDO_A)) {
-                  int evdoEcio = signalStrength.getEvdoEcio();
-                  int evdoSnr = signalStrength.getEvdoSnr();
-                  int levelEvdoEcio = 0;
-                  int levelEvdoSnr = 0;
-
-                  // Ec/Io are in dB*10
-                  if (evdoEcio >= -650) levelEvdoEcio = 4;
-                  else if (evdoEcio >= -750) levelEvdoEcio = 3;
-                  else if (evdoEcio >= -900) levelEvdoEcio = 2;
-                  else if (evdoEcio >= -1050) levelEvdoEcio = 1;
-                  else levelEvdoEcio = 0;
-
-                  if (evdoSnr > 7) levelEvdoSnr = 4;
-                  else if (evdoSnr > 5) levelEvdoSnr = 3;
-                  else if (evdoSnr > 3) levelEvdoSnr = 2;
-                  else if (evdoSnr > 1) levelEvdoSnr = 1;
-                  else levelEvdoSnr = 0;
-
-                  evdoIconLevel = (levelEvdoEcio < levelEvdoSnr) ? levelEvdoEcio : levelEvdoSnr;
-            }
-            // TODO(): There is a bug open regarding what should be sent.
-            return (cdmaIconLevel > evdoIconLevel) ?  cdmaIconLevel : evdoIconLevel;
-
-        }
-
-
-        private int asuToSignal(SignalStrength signalStrength) {
-            if (signalStrength.isGsm()) {
-                return gsmAsuToSignal(signalStrength);
-            } else {
-                return cdmaDbmEcioToSignal(signalStrength);
-            }
-        }
-
-
-        /* convert [0,5] signal strength to a rssi signal strength for CSQ
-         * which is [0,31]. Despite the same scale, this is not the same value
-         * as ASU.
-         */
-        private int signalToRssi(int signal) {
-            // using C4A suggested values
-            switch (signal) {
-            case 0: return 0;
-            case 1: return 4;
-            case 2: return 8;
-            case 3: return 13;
-            case 4: return 19;
-            case 5: return 31;
-            }
-            return 0;
-        }
-
-
-        private final BroadcastReceiver mStateReceiver = new BroadcastReceiver() {
-            @Override
-            public void onReceive(Context context, Intent intent) {
-                if (intent.getAction().equals(Intent.ACTION_BATTERY_CHANGED)) {
-                    Message msg = mHandler.obtainMessage(BATTERY_CHANGED, intent);
-                    mHandler.sendMessage(msg);
-                } else if (intent.getAction().equals(
-                            TelephonyIntents.ACTION_SIGNAL_STRENGTH_CHANGED)) {
-                    Message msg = mHandler.obtainMessage(SIGNAL_STRENGTH_CHANGED,
-                                                                    intent);
-                    mHandler.sendMessage(msg);
-                } else if (intent.getAction().equals(
-                    BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED)) {
-                    int state = intent.getIntExtra(BluetoothProfile.EXTRA_STATE,
-                        BluetoothProfile.STATE_DISCONNECTED);
-                    int oldState = intent.getIntExtra(BluetoothProfile.EXTRA_PREVIOUS_STATE,
-                        BluetoothProfile.STATE_DISCONNECTED);
-                    BluetoothDevice device =
-                            intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
-
-
-                    // We are only concerned about Connected sinks to suspend and resume
-                    // them. We can safely ignore SINK_STATE_CHANGE for other devices.
-                    if (device == null || (mA2dpDevice != null && !device.equals(mA2dpDevice))) {
-                        return;
-                    }
-
-                    synchronized (BluetoothHandsfree.this) {
-                        mA2dpState = state;
-                        if (state == BluetoothProfile.STATE_DISCONNECTED) {
-                            mA2dpDevice = null;
-                        } else {
-                            mA2dpDevice = device;
-                        }
-                        if (oldState == BluetoothA2dp.STATE_PLAYING &&
-                            mA2dpState == BluetoothProfile.STATE_CONNECTED) {
-                            if (mA2dpSuspended) {
-                                if (mPendingSco) {
-                                    mHandler.removeMessages(MESSAGE_CHECK_PENDING_SCO);
-                                    if (DBG) log("A2DP suspended, completing SCO");
-                                    connectScoThread();
-                                    mPendingSco = false;
-                                }
-                            }
-                        }
-                    }
-                } else if (intent.getAction().
-                           equals(BluetoothDevice.ACTION_CONNECTION_ACCESS_REPLY)) {
-                    mPhonebook.handleAccessPermissionResult(intent);
-                }
-            }
-        };
-
-        private synchronized void updateBatteryState(Intent intent) {
-            int batteryLevel = intent.getIntExtra("level", -1);
-            int scale = intent.getIntExtra("scale", -1);
-            if (batteryLevel == -1 || scale == -1) {
-                return;  // ignore
-            }
-            batteryLevel = batteryLevel * 5 / scale;
-            if (mBattchg != batteryLevel) {
-                mBattchg = batteryLevel;
-                if (sendUpdate()) {
-                    sendURC("+CIEV: 7," + mBattchg);
-                }
-            }
-        }
-
-        private synchronized void updateSignalState(Intent intent) {
-            // NOTE this function is called by the BroadcastReceiver mStateReceiver after intent
-            // ACTION_SIGNAL_STRENGTH_CHANGED and by the DebugThread mDebugThread
-            if (!isHeadsetConnected()) {
-                return;
-            }
-
-            SignalStrength signalStrength = SignalStrength.newFromBundle(intent.getExtras());
-            int signal;
-
-            if (signalStrength != null) {
-                signal = asuToSignal(signalStrength);
-                mRssi = signalToRssi(signal);  // no unsolicited CSQ
-                if (signal != mSignal) {
-                    mSignal = signal;
-                    if (sendUpdate()) {
-                        sendURC("+CIEV: 5," + mSignal);
-                    }
-                }
-            } else {
-                Log.e(TAG, "Signal Strength null");
-            }
-        }
-
-        private synchronized void updateServiceState(boolean sendUpdate, ServiceState state) {
-            int service = state.getState() == ServiceState.STATE_IN_SERVICE ? 1 : 0;
-            int roam = state.getRoaming() ? 1 : 0;
-            int stat;
-            AtCommandResult result = new AtCommandResult(AtCommandResult.UNSOLICITED);
-            mServiceState = state;
-            if (service == 0) {
-                stat = 0;
-            } else {
-                stat = (roam == 1) ? 5 : 1;
-            }
-
-            if (service != mService) {
-                mService = service;
-                if (sendUpdate) {
-                    result.addResponse("+CIEV: 1," + mService);
-                }
-            }
-            if (roam != mRoam) {
-                mRoam = roam;
-                if (sendUpdate) {
-                    result.addResponse("+CIEV: 6," + mRoam);
-                }
-            }
-            if (stat != mStat) {
-                mStat = stat;
-                if (sendUpdate) {
-                    result.addResponse(toCregString());
-                }
-            }
-
-            sendURC(result.toString());
-        }
-
-        private synchronized void handlePreciseCallStateChange(boolean sendUpdate,
-                Connection connection) {
-            int call = 0;
-            int callsetup = 0;
-            int callheld = 0;
-            int prevCallsetup = mCallsetup;
-            AtCommandResult result = new AtCommandResult(AtCommandResult.UNSOLICITED);
-            Call foregroundCall = mCM.getActiveFgCall();
-            Call backgroundCall = mCM.getFirstActiveBgCall();
-            Call ringingCall = mCM.getFirstActiveRingingCall();
-
-            if (VDBG) log("updatePhoneState()");
-
-            // This function will get called when the Precise Call State
-            // {@link Call.State} changes. Hence, we might get this update
-            // even if the {@link PhoneConstants.state} is same as before.
-            // Check for the same.
-
-            PhoneConstants.State newState = mCM.getState();
-            if (newState != mPhoneState) {
-                mPhoneState = newState;
-                switch (mPhoneState) {
-                case IDLE:
-                    mUserWantsAudio = true;  // out of call - reset state
-                    audioOff();
-                    break;
-                default:
-                    callStarted();
-                }
-            }
-
-            switch(foregroundCall.getState()) {
-            case ACTIVE:
-                call = 1;
-                mAudioPossible = true;
-                break;
-            case DIALING:
-                callsetup = 2;
-                mAudioPossible = true;
-                // We also need to send a Call started indication
-                // for cases where the 2nd MO was initiated was
-                // from a *BT hands free* and is waiting for a
-                // +BLND: OK response
-                // There is a special case handling of the same case
-                // for CDMA below
-                if (mCM.getFgPhone().getPhoneType() == PhoneConstants.PHONE_TYPE_GSM) {
-                    callStarted();
-                }
-                break;
-            case ALERTING:
-                callsetup = 3;
-                // Open the SCO channel for the outgoing call.
-                mCallStartTime = System.currentTimeMillis();
-                audioOn();
-                mAudioPossible = true;
-                break;
-            case DISCONNECTING:
-                // This is a transient state, we don't want to send
-                // any AT commands during this state.
-                call = mCall;
-                callsetup = mCallsetup;
-                callheld = mCallheld;
-                break;
-            default:
-                mAudioPossible = false;
-            }
-
-            switch(ringingCall.getState()) {
-            case INCOMING:
-            case WAITING:
-                callsetup = 1;
-                break;
-            case DISCONNECTING:
-                // This is a transient state, we don't want to send
-                // any AT commands during this state.
-                call = mCall;
-                callsetup = mCallsetup;
-                callheld = mCallheld;
-                break;
-            }
-
-            switch(backgroundCall.getState()) {
-            case HOLDING:
-                if (call == 1) {
-                    callheld = 1;
-                } else {
-                    call = 1;
-                    callheld = 2;
-                }
-                break;
-            case DISCONNECTING:
-                // This is a transient state, we don't want to send
-                // any AT commands during this state.
-                call = mCall;
-                callsetup = mCallsetup;
-                callheld = mCallheld;
-                break;
-            }
-
-            if (mCall != call) {
-                if (call == 1) {
-                    // This means that a call has transitioned from NOT ACTIVE to ACTIVE.
-                    // Switch on audio.
-                    mCallStartTime = System.currentTimeMillis();
-                    audioOn();
-                }
-                mCall = call;
-                if (sendUpdate) {
-                    result.addResponse("+CIEV: 2," + mCall);
-                }
-            }
-            if (mCallsetup != callsetup) {
-                mCallsetup = callsetup;
-                if (sendUpdate) {
-                    // If mCall = 0, send CIEV
-                    // mCall = 1, mCallsetup = 0, send CIEV
-                    // mCall = 1, mCallsetup = 1, send CIEV after CCWA,
-                    // if 3 way supported.
-                    // mCall = 1, mCallsetup = 2 / 3 -> send CIEV,
-                    // if 3 way is supported
-                    if (mCall != 1 || mCallsetup == 0 ||
-                        mCallsetup != 1 && (mRemoteBrsf & BRSF_HF_CW_THREE_WAY_CALLING) != 0x0) {
-                        result.addResponse("+CIEV: 3," + mCallsetup);
-                    }
-                }
-            }
-
-            if (mCM.getDefaultPhone().getPhoneType() == PhoneConstants.PHONE_TYPE_CDMA) {
-                PhoneApp app = PhoneApp.getInstance();
-                if (app.cdmaPhoneCallState != null) {
-                    CdmaPhoneCallState.PhoneCallState currCdmaThreeWayCallState =
-                            app.cdmaPhoneCallState.getCurrentCallState();
-                    CdmaPhoneCallState.PhoneCallState prevCdmaThreeWayCallState =
-                        app.cdmaPhoneCallState.getPreviousCallState();
-
-                    log("CDMA call state: " + currCdmaThreeWayCallState + " prev state:" +
-                        prevCdmaThreeWayCallState);
-                    callheld = getCdmaCallHeldStatus(currCdmaThreeWayCallState,
-                                                     prevCdmaThreeWayCallState);
-
-                    if (mCdmaThreeWayCallState != currCdmaThreeWayCallState) {
-                        // In CDMA, the network does not provide any feedback
-                        // to the phone when the 2nd MO call goes through the
-                        // stages of DIALING > ALERTING -> ACTIVE we fake the
-                        // sequence
-                        if ((currCdmaThreeWayCallState ==
-                                CdmaPhoneCallState.PhoneCallState.THRWAY_ACTIVE)
-                                    && app.cdmaPhoneCallState.IsThreeWayCallOrigStateDialing()) {
-                            mAudioPossible = true;
-                            if (sendUpdate) {
-                                if ((mRemoteBrsf & BRSF_HF_CW_THREE_WAY_CALLING) != 0x0) {
-                                    result.addResponse("+CIEV: 3,2");
-                                    // Mimic putting the call on hold
-                                    result.addResponse("+CIEV: 4,1");
-                                    mCallheld = callheld;
-                                    result.addResponse("+CIEV: 3,3");
-                                    result.addResponse("+CIEV: 3,0");
-                                }
-                            }
-                            // We also need to send a Call started indication
-                            // for cases where the 2nd MO was initiated was
-                            // from a *BT hands free* and is waiting for a
-                            // +BLND: OK response
-                            callStarted();
-                        }
-
-                        // In CDMA, the network does not provide any feedback to
-                        // the phone when a user merges a 3way call or swaps
-                        // between two calls we need to send a CIEV response
-                        // indicating that a call state got changed which should
-                        // trigger a CLCC update request from the BT client.
-                        if (currCdmaThreeWayCallState ==
-                                CdmaPhoneCallState.PhoneCallState.CONF_CALL &&
-                                prevCdmaThreeWayCallState ==
-                                  CdmaPhoneCallState.PhoneCallState.THRWAY_ACTIVE) {
-                            mAudioPossible = true;
-                            if (sendUpdate) {
-                                if ((mRemoteBrsf & BRSF_HF_CW_THREE_WAY_CALLING) != 0x0) {
-                                    result.addResponse("+CIEV: 2,1");
-                                    result.addResponse("+CIEV: 3,0");
-                                }
-                            }
-                        }
-                    }
-                    mCdmaThreeWayCallState = currCdmaThreeWayCallState;
-                }
-            }
-
-            boolean callsSwitched;
-
-            if (mCM.getDefaultPhone().getPhoneType() == PhoneConstants.PHONE_TYPE_CDMA &&
-                mCdmaThreeWayCallState == CdmaPhoneCallState.PhoneCallState.CONF_CALL) {
-                callsSwitched = mCdmaCallsSwapped;
-            } else {
-                callsSwitched =
-                    (callheld == 1 && ! (backgroundCall.getEarliestConnectTime() ==
-                        mBgndEarliestConnectionTime));
-                mBgndEarliestConnectionTime = backgroundCall.getEarliestConnectTime();
-            }
-
-
-            if (mCallheld != callheld || callsSwitched) {
-                mCallheld = callheld;
-                if (sendUpdate) {
-                    result.addResponse("+CIEV: 4," + mCallheld);
-                }
-            }
-
-            if (callsetup == 1 && callsetup != prevCallsetup) {
-                // new incoming call
-                String number = null;
-                int type = 128;
-                // find incoming phone number and type
-                if (connection == null) {
-                    connection = ringingCall.getEarliestConnection();
-                    if (connection == null) {
-                        Log.e(TAG, "Could not get a handle on Connection object for new " +
-                              "incoming call");
-                    }
-                }
-                if (connection != null) {
-                    number = connection.getAddress();
-                    if (number != null) {
-                        type = PhoneNumberUtils.toaFromString(number);
-                    }
-                }
-                if (number == null) {
-                    number = "";
-                }
-                if ((call != 0 || callheld != 0) && sendUpdate) {
-                    // call waiting
-                    if ((mRemoteBrsf & BRSF_HF_CW_THREE_WAY_CALLING) != 0x0) {
-                        result.addResponse("+CCWA: \"" + number + "\"," + type);
-                        result.addResponse("+CIEV: 3," + callsetup);
-                    }
-                } else {
-                    // regular new incoming call
-                    mRingingNumber = number;
-                    mRingingType = type;
-                    mIgnoreRing = false;
-                    mStopRing = false;
-
-                    if ((mLocalBrsf & BRSF_AG_IN_BAND_RING) != 0x0) {
-                        mCallStartTime = System.currentTimeMillis();
-                        audioOn();
-                    }
-                    result.addResult(ring());
-                }
-            }
-            sendURC(result.toString());
-        }
-
-        private int getCdmaCallHeldStatus(CdmaPhoneCallState.PhoneCallState currState,
-                                  CdmaPhoneCallState.PhoneCallState prevState) {
-            int callheld;
-            // Update the Call held information
-            if (currState == CdmaPhoneCallState.PhoneCallState.CONF_CALL) {
-                if (prevState == CdmaPhoneCallState.PhoneCallState.THRWAY_ACTIVE) {
-                    callheld = 0; //0: no calls held, as now *both* the caller are active
-                } else {
-                    callheld = 1; //1: held call and active call, as on answering a
-                            // Call Waiting, one of the caller *is* put on hold
-                }
-            } else if (currState == CdmaPhoneCallState.PhoneCallState.THRWAY_ACTIVE) {
-                callheld = 1; //1: held call and active call, as on make a 3 Way Call
-                        // the first caller *is* put on hold
-            } else {
-                callheld = 0; //0: no calls held as this is a SINGLE_ACTIVE call
-            }
-            return callheld;
-        }
-
-
-        private AtCommandResult ring() {
-            if (sendRingUpdate()) {
-                AtCommandResult result = new AtCommandResult(AtCommandResult.UNSOLICITED);
-                result.addResponse("RING");
-                if (sendClipUpdate()) {
-                    result.addResponse("+CLIP: \"" + mRingingNumber + "\"," + mRingingType);
-                }
-
-                Message msg = mStateChangeHandler.obtainMessage(RING);
-                mStateChangeHandler.sendMessageDelayed(msg, 3000);
-                return result;
-            }
-            return null;
-        }
-
-        private synchronized String toCregString() {
-            return new String("+CREG: 1," + mStat);
-        }
-
-        private synchronized void updateCallHeld() {
-            if (mCallheld != 0) {
-                mCallheld = 0;
-                sendURC("+CIEV: 4,0");
-            }
-        }
-
-        private synchronized AtCommandResult toCindResult() {
-            AtCommandResult result = new AtCommandResult(AtCommandResult.OK);
-            int call, call_setup;
-
-            // Handsfree carkits expect that +CIND is properly responded to.
-            // Hence we ensure that a proper response is sent for the virtual call too.
-            if (isVirtualCallInProgress()) {
-                call = 1;
-                call_setup = 0;
-            } else {
-                // regular phone call
-                call = mCall;
-                call_setup = mCallsetup;
-            }
-
-            mSignal = asuToSignal(mCM.getDefaultPhone().getSignalStrength());
-            String status = "+CIND: " + mService + "," + call + "," + call_setup + "," +
-                            mCallheld + "," + mSignal + "," + mRoam + "," + mBattchg;
-            result.addResponse(status);
-            return result;
-        }
-
-        private synchronized AtCommandResult toCsqResult() {
-            AtCommandResult result = new AtCommandResult(AtCommandResult.OK);
-            String status = "+CSQ: " + mRssi + ",99";
-            result.addResponse(status);
-            return result;
-        }
-
-
-        private synchronized AtCommandResult getCindTestResult() {
-            return new AtCommandResult("+CIND: (\"service\",(0-1))," + "(\"call\",(0-1))," +
-                        "(\"callsetup\",(0-3)),(\"callheld\",(0-2)),(\"signal\",(0-5))," +
-                        "(\"roam\",(0-1)),(\"battchg\",(0-5))");
-        }
-
-        private synchronized void ignoreRing() {
-            mCallsetup = 0;
-            mIgnoreRing = true;
-            if (sendUpdate()) {
-                sendURC("+CIEV: 3," + mCallsetup);
-            }
-        }
-
-        private void scoClosed() {
-            // sync on mUserWantsAudio change
-            synchronized(BluetoothHandsfree.this) {
-                if (mUserWantsAudio &&
-                    System.currentTimeMillis() - mCallStartTime < RETRY_SCO_TIME_WINDOW) {
-                    Message msg = mHandler.obtainMessage(SCO_CONNECTION_CHECK);
-                    mHandler.sendMessage(msg);
-                }
-            }
-        }
-    };
-
-    private static final int SCO_CLOSED = 3;
-    private static final int CHECK_CALL_STARTED = 4;
-    private static final int CHECK_VOICE_RECOGNITION_STARTED = 5;
-    private static final int MESSAGE_CHECK_PENDING_SCO = 6;
-    private static final int SCO_AUDIO_STATE = 7;
-    private static final int SCO_CONNECTION_CHECK = 8;
-    private static final int BATTERY_CHANGED = 9;
-    private static final int SIGNAL_STRENGTH_CHANGED = 10;
-
-    private final class HandsfreeMessageHandler extends Handler {
-        private HandsfreeMessageHandler(Looper looper) {
-            super(looper);
-        }
-
-        @Override
-        public void handleMessage(Message msg) {
-            switch (msg.what) {
-            case SCO_CLOSED:
-                synchronized (BluetoothHandsfree.this) {
-                    // synchronized
-                    // Make atomic against audioOn, userWantsAudioOn
-                    // TODO finer lock to decouple from other call flow such as
-                    //      mWaitingForCallStart change
-
-                    audioOff();
-                    // notify mBluetoothPhoneState that the SCO channel has closed
-                    mBluetoothPhoneState.scoClosed();
-                }
-                break;
-            case CHECK_CALL_STARTED:
-                synchronized (BluetoothHandsfree.this) {
-                    // synchronized
-                    // Protect test/change of mWaitingForCallStart
-                    if (mWaitingForCallStart) {
-                        mWaitingForCallStart = false;
-                        Log.e(TAG, "Timeout waiting for call to start");
-                        sendURC("ERROR");
-                        if (mStartCallWakeLock.isHeld()) {
-                            mStartCallWakeLock.release();
-                        }
-                    }
-                }
-                break;
-            case CHECK_VOICE_RECOGNITION_STARTED:
-                synchronized (BluetoothHandsfree.this) {
-                    // synchronized
-                    // Protect test/change of mWaitingForVoiceRecognition
-                    if (mWaitingForVoiceRecognition) {
-                        mWaitingForVoiceRecognition = false;
-                        Log.e(TAG, "Timeout waiting for voice recognition to start");
-                        sendURC("ERROR");
-                    }
-                }
-                break;
-            case MESSAGE_CHECK_PENDING_SCO:
-                synchronized (BluetoothHandsfree.this) {
-                    // synchronized
-                    // Protect test/change of mPendingSco
-                    if (mPendingSco && isA2dpMultiProfile()) {
-                        Log.w(TAG, "Timeout suspending A2DP for SCO (mA2dpState = " +
-                                mA2dpState + "). Starting SCO anyway");
-                        connectScoThread();
-                        mPendingSco = false;
-                    }
-                }
-                break;
-            case SCO_AUDIO_STATE:
-                BluetoothDevice device = (BluetoothDevice) msg.obj;
-                if (getAudioState(device) == BluetoothHeadset.STATE_AUDIO_CONNECTING) {
-                    setAudioState(BluetoothHeadset.STATE_AUDIO_DISCONNECTED, device);
-                }
-                break;
-            case SCO_CONNECTION_CHECK:
-                synchronized (mBluetoothPhoneState) {
-                    // synchronized on mCall change
-                    if (mBluetoothPhoneState.mCall == 1) {
-                        // Sometimes, the SCO channel is torn down by HF with no reason.
-                        // Because we are still in active call, reconnect SCO.
-                        // audioOn does nothing if the SCO is already on.
-                        audioOn();
-                    }
-                }
-                break;
-            case BATTERY_CHANGED:
-                mBluetoothPhoneState.updateBatteryState((Intent) msg.obj);
-                break;
-            case SIGNAL_STRENGTH_CHANGED:
-                mBluetoothPhoneState.updateSignalState((Intent) msg.obj);
-                break;
-            }
-        }
-    }
-
-    private synchronized void setAudioState(int state, BluetoothDevice device) {
-        if (VDBG) log("setAudioState(" + state + ")");
-        if (mBluetoothHeadset == null) {
-            mAdapter.getProfileProxy(mContext, mProfileListener, BluetoothProfile.HEADSET);
-            mPendingAudioState = true;
-            mAudioState = state;
-            return;
-        }
-        mBluetoothHeadset.setAudioState(device, state);
-    }
-
-    private synchronized int getAudioState(BluetoothDevice device) {
-        if (mBluetoothHeadset == null) return BluetoothHeadset.STATE_AUDIO_DISCONNECTED;
-        return mBluetoothHeadset.getAudioState(device);
-    }
-
-    private BluetoothProfile.ServiceListener mProfileListener =
-            new BluetoothProfile.ServiceListener() {
-        public void onServiceConnected(int profile, BluetoothProfile proxy) {
-            if (profile == BluetoothProfile.HEADSET) {
-                mBluetoothHeadset = (BluetoothHeadset) proxy;
-                synchronized(BluetoothHandsfree.this) {
-                    if (mPendingAudioState) {
-                        mBluetoothHeadset.setAudioState(mHeadset.getRemoteDevice(), mAudioState);
-                        mPendingAudioState = false;
-                    }
-                }
-            } else if (profile == BluetoothProfile.A2DP) {
-                mA2dp = (BluetoothA2dp) proxy;
-            }
-        }
-        public void onServiceDisconnected(int profile) {
-            if (profile == BluetoothProfile.HEADSET) {
-                mBluetoothHeadset = null;
-            } else if (profile == BluetoothProfile.A2DP) {
-                mA2dp = null;
-            }
-        }
-    };
-
-    /*
-     * Put the AT command, company ID, arguments, and device in an Intent and broadcast it.
-     */
-    private void broadcastVendorSpecificEventIntent(String command,
-                                                    int companyId,
-                                                    int commandType,
-                                                    Object[] arguments,
-                                                    BluetoothDevice device) {
-        if (VDBG) log("broadcastVendorSpecificEventIntent(" + command + ")");
-        Intent intent =
-                new Intent(BluetoothHeadset.ACTION_VENDOR_SPECIFIC_HEADSET_EVENT);
-        intent.putExtra(BluetoothHeadset.EXTRA_VENDOR_SPECIFIC_HEADSET_EVENT_CMD, command);
-        intent.putExtra(BluetoothHeadset.EXTRA_VENDOR_SPECIFIC_HEADSET_EVENT_CMD_TYPE,
-                        commandType);
-        // assert: all elements of args are Serializable
-        intent.putExtra(BluetoothHeadset.EXTRA_VENDOR_SPECIFIC_HEADSET_EVENT_ARGS, arguments);
-        intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device);
-
-        intent.addCategory(BluetoothHeadset.VENDOR_SPECIFIC_HEADSET_EVENT_COMPANY_ID_CATEGORY
-            + "." + Integer.toString(companyId));
-
-        mContext.sendBroadcast(intent, android.Manifest.permission.BLUETOOTH);
-    }
-
-    void updateBtHandsfreeAfterRadioTechnologyChange() {
-        if (VDBG) Log.d(TAG, "updateBtHandsfreeAfterRadioTechnologyChange...");
-
-        mBluetoothPhoneState.updateBtPhoneStateAfterRadioTechnologyChange();
-    }
-
-    /** Request to establish SCO (audio) connection to bluetooth
-     * headset/handsfree, if one is connected. Does not block.
-     * Returns false if the user has requested audio off, or if there
-     * is some other immediate problem that will prevent BT audio.
-     */
-    /* package */ synchronized boolean audioOn() {
-        if (VDBG) log("audioOn()");
-        if (!isHeadsetConnected()) {
-            if (DBG) log("audioOn(): headset is not connected!");
-            return false;
-        }
-        if (mHeadsetType == TYPE_HANDSFREE && !mServiceConnectionEstablished) {
-            if (DBG) log("audioOn(): service connection not yet established!");
-            return false;
-        }
-
-        if (mConnectedSco != null) {
-            if (DBG) log("audioOn(): audio is already connected");
-            return true;
-        }
-
-        if (!mUserWantsAudio) {
-            if (DBG) log("audioOn(): user requested no audio, ignoring");
-            return false;
-        }
-
-        if (mPendingSco) {
-            if (DBG) log("audioOn(): SCO already pending");
-            return true;
-        }
-
-        mA2dpSuspended = false;
-        mPendingSco = false;
-        if (isA2dpMultiProfile() && mA2dpState == BluetoothA2dp.STATE_PLAYING) {
-            if (DBG) log("suspending A2DP stream for SCO");
-            mA2dpSuspended = mA2dp.suspendSink(mA2dpDevice);
-            if (mA2dpSuspended) {
-                mPendingSco = true;
-                Message msg = mHandler.obtainMessage(MESSAGE_CHECK_PENDING_SCO);
-                mHandler.sendMessageDelayed(msg, 2000);
-            } else {
-                Log.w(TAG, "Could not suspend A2DP stream for SCO, going ahead with SCO");
-            }
-        }
-
-        if (!mPendingSco) {
-            connectScoThread();
-        }
-
-        return true;
-    }
-
-    /** Used to indicate the user requested BT audio on.
-     *  This will establish SCO (BT audio), even if the user requested it off
-     *  previously on this call.
-     */
-    /* package */ synchronized void userWantsAudioOn() {
-        mUserWantsAudio = true;
-        audioOn();
-    }
-    /** Used to indicate the user requested BT audio off.
-     *  This will prevent us from establishing BT audio again during this call
-     *  if audioOn() is called.
-     */
-    /* package */ synchronized void userWantsAudioOff() {
-        mUserWantsAudio = false;
-        audioOff();
-    }
-
-    /** Request to disconnect SCO (audio) connection to bluetooth
-     * headset/handsfree, if one is connected. Does not block.
-     */
-    /* package */ synchronized void audioOff() {
-        if (VDBG) log("audioOff(): mPendingSco: " + mPendingSco +
-                ", mConnectedSco: " + mConnectedSco +
-                ", mA2dpState: " + mA2dpState +
-                ", mA2dpSuspended: " + mA2dpSuspended);
-
-        if (mA2dpSuspended) {
-            if (isA2dpMultiProfile()) {
-                if (DBG) log("resuming A2DP stream after disconnecting SCO");
-                mA2dp.resumeSink(mA2dpDevice);
-            }
-            mA2dpSuspended = false;
-        }
-
-        mPendingSco = false;
-
-        if (mSignalScoCloseThread != null) {
-            mSignalScoCloseThread.shutdown();
-            mSignalScoCloseThread = null;
-        }
-
-        // Sync with setting mConnectScoThread to null to assure the validity of
-        // the condition
-        synchronized (ScoSocketConnectThread.class) {
-            if (mConnectScoThread != null) {
-                mConnectScoThread.shutdown();
-                resetConnectScoThread();
-            }
-        }
-
-        closeConnectedSco();    // Should be closed already, but just in case
-    }
-
-    /* package */ boolean isAudioOn() {
-        return (mConnectedSco != null);
-    }
-
-    private boolean isA2dpMultiProfile() {
-        return mA2dp != null && mHeadset != null && mA2dpDevice != null &&
-                mA2dpDevice.equals(mHeadset.getRemoteDevice());
-    }
-
-    /* package */ void ignoreRing() {
-        mBluetoothPhoneState.ignoreRing();
-    }
-
-    private void sendURC(String urc) {
-        if (isHeadsetConnected()) {
-            mHeadset.sendURC(urc);
-        }
-    }
-
-    /** helper to redial last dialled number */
-    private AtCommandResult redial() {
-        String number = mPhonebook.getLastDialledNumber();
-        if (number == null) {
-            // spec seems to suggest sending ERROR if we dont have a
-            // number to redial
-            if (VDBG) log("Bluetooth redial requested (+BLDN), but no previous " +
-                  "outgoing calls found. Ignoring");
-            return new AtCommandResult(AtCommandResult.ERROR);
-        }
-        // Outgoing call initiated by the handsfree device
-        // Send terminateScoUsingVirtualVoiceCall
-        terminateScoUsingVirtualVoiceCall();
-        Intent intent = new Intent(Intent.ACTION_CALL_PRIVILEGED,
-                Uri.fromParts(Constants.SCHEME_TEL, number, null));
-        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-        mContext.startActivity(intent);
-
-        // We do not immediately respond OK, wait until we get a phone state
-        // update. If we return OK now and the handsfree immeidately requests
-        // our phone state it will say we are not in call yet which confuses
-        // some devices
-        expectCallStart();
-        return new AtCommandResult(AtCommandResult.UNSOLICITED);  // send nothing
-    }
-
-    /** Build the +CLCC result
-     *  The complexity arises from the fact that we need to maintain the same
-     *  CLCC index even as a call moves between states. */
-    private synchronized AtCommandResult gsmGetClccResult() {
-        // Collect all known connections
-        Connection[] clccConnections = new Connection[GSM_MAX_CONNECTIONS];  // indexed by CLCC index
-        LinkedList<Connection> newConnections = new LinkedList<Connection>();
-        LinkedList<Connection> connections = new LinkedList<Connection>();
-
-        Call foregroundCall = mCM.getActiveFgCall();
-        Call backgroundCall = mCM.getFirstActiveBgCall();
-        Call ringingCall = mCM.getFirstActiveRingingCall();
-
-        if (ringingCall.getState().isAlive()) {
-            connections.addAll(ringingCall.getConnections());
-        }
-        if (foregroundCall.getState().isAlive()) {
-            connections.addAll(foregroundCall.getConnections());
-        }
-        if (backgroundCall.getState().isAlive()) {
-            connections.addAll(backgroundCall.getConnections());
-        }
-
-        // Mark connections that we already known about
-        boolean clccUsed[] = new boolean[GSM_MAX_CONNECTIONS];
-        for (int i = 0; i < GSM_MAX_CONNECTIONS; i++) {
-            clccUsed[i] = mClccUsed[i];
-            mClccUsed[i] = false;
-        }
-        for (Connection c : connections) {
-            boolean found = false;
-            long timestamp = c.getCreateTime();
-            for (int i = 0; i < GSM_MAX_CONNECTIONS; i++) {
-                if (clccUsed[i] && timestamp == mClccTimestamps[i]) {
-                    mClccUsed[i] = true;
-                    found = true;
-                    clccConnections[i] = c;
-                    break;
-                }
-            }
-            if (!found) {
-                newConnections.add(c);
-            }
-        }
-
-        // Find a CLCC index for new connections
-        while (!newConnections.isEmpty()) {
-            // Find lowest empty index
-            int i = 0;
-            while (mClccUsed[i]) i++;
-            // Find earliest connection
-            long earliestTimestamp = newConnections.get(0).getCreateTime();
-            Connection earliestConnection = newConnections.get(0);
-            for (int j = 0; j < newConnections.size(); j++) {
-                long timestamp = newConnections.get(j).getCreateTime();
-                if (timestamp < earliestTimestamp) {
-                    earliestTimestamp = timestamp;
-                    earliestConnection = newConnections.get(j);
-                }
-            }
-
-            // update
-            mClccUsed[i] = true;
-            mClccTimestamps[i] = earliestTimestamp;
-            clccConnections[i] = earliestConnection;
-            newConnections.remove(earliestConnection);
-        }
-
-        // Build CLCC
-        AtCommandResult result = new AtCommandResult(AtCommandResult.OK);
-        for (int i = 0; i < clccConnections.length; i++) {
-            if (mClccUsed[i]) {
-                String clccEntry = connectionToClccEntry(i, clccConnections[i]);
-                if (clccEntry != null) {
-                    result.addResponse(clccEntry);
-                }
-            }
-        }
-
-        return result;
-    }
-
-    /** Convert a Connection object into a single +CLCC result */
-    private String connectionToClccEntry(int index, Connection c) {
-        int state;
-        switch (c.getState()) {
-        case ACTIVE:
-            state = 0;
-            break;
-        case HOLDING:
-            state = 1;
-            break;
-        case DIALING:
-            state = 2;
-            break;
-        case ALERTING:
-            state = 3;
-            break;
-        case INCOMING:
-            state = 4;
-            break;
-        case WAITING:
-            state = 5;
-            break;
-        default:
-            return null;  // bad state
-        }
-
-        int mpty = 0;
-        Call call = c.getCall();
-        if (call != null) {
-            mpty = call.isMultiparty() ? 1 : 0;
-        }
-
-        int direction = c.isIncoming() ? 1 : 0;
-
-        String number = c.getAddress();
-        int type = -1;
-        if (number != null) {
-            type = PhoneNumberUtils.toaFromString(number);
-        }
-
-        String result = "+CLCC: " + (index + 1) + "," + direction + "," + state + ",0," + mpty;
-        if (number != null) {
-            result += ",\"" + number + "\"," + type;
-        }
-        return result;
-    }
-
-    /** Build the +CLCC result for CDMA
-     *  The complexity arises from the fact that we need to maintain the same
-     *  CLCC index even as a call moves between states. */
-    private synchronized AtCommandResult cdmaGetClccResult() {
-        // In CDMA at one time a user can have only two live/active connections
-        Connection[] clccConnections = new Connection[CDMA_MAX_CONNECTIONS];// indexed by CLCC index
-        Call foregroundCall = mCM.getActiveFgCall();
-        Call ringingCall = mCM.getFirstActiveRingingCall();
-
-        Call.State ringingCallState = ringingCall.getState();
-        // If the Ringing Call state is INCOMING, that means this is the very first call
-        // hence there should not be any Foreground Call
-        if (ringingCallState == Call.State.INCOMING) {
-            if (VDBG) log("Filling clccConnections[0] for INCOMING state");
-            clccConnections[0] = ringingCall.getLatestConnection();
-        } else if (foregroundCall.getState().isAlive()) {
-            // Getting Foreground Call connection based on Call state
-            if (ringingCall.isRinging()) {
-                if (VDBG) log("Filling clccConnections[0] & [1] for CALL WAITING state");
-                clccConnections[0] = foregroundCall.getEarliestConnection();
-                clccConnections[1] = ringingCall.getLatestConnection();
-            } else {
-                if (foregroundCall.getConnections().size() <= 1) {
-                    // Single call scenario
-                    if (VDBG) log("Filling clccConnections[0] with ForgroundCall latest connection");
-                    clccConnections[0] = foregroundCall.getLatestConnection();
-                } else {
-                    // Multiple Call scenario. This would be true for both
-                    // CONF_CALL and THRWAY_ACTIVE state
-                    if (VDBG) log("Filling clccConnections[0] & [1] with ForgroundCall connections");
-                    clccConnections[0] = foregroundCall.getEarliestConnection();
-                    clccConnections[1] = foregroundCall.getLatestConnection();
-                }
-            }
-        }
-
-        // Update the mCdmaIsSecondCallActive flag based on the Phone call state
-        if (PhoneApp.getInstance().cdmaPhoneCallState.getCurrentCallState()
-                == CdmaPhoneCallState.PhoneCallState.SINGLE_ACTIVE) {
-            cdmaSetSecondCallState(false);
-        } else if (PhoneApp.getInstance().cdmaPhoneCallState.getCurrentCallState()
-                == CdmaPhoneCallState.PhoneCallState.THRWAY_ACTIVE) {
-            cdmaSetSecondCallState(true);
-        }
-
-        // Build CLCC
-        AtCommandResult result = new AtCommandResult(AtCommandResult.OK);
-        for (int i = 0; (i < clccConnections.length) && (clccConnections[i] != null); i++) {
-            String clccEntry = cdmaConnectionToClccEntry(i, clccConnections[i]);
-            if (clccEntry != null) {
-                result.addResponse(clccEntry);
-            }
-        }
-
-        return result;
-    }
-
-    /** Convert a Connection object into a single +CLCC result for CDMA phones */
-    private String cdmaConnectionToClccEntry(int index, Connection c) {
-        int state;
-        PhoneApp app = PhoneApp.getInstance();
-        CdmaPhoneCallState.PhoneCallState currCdmaCallState =
-                app.cdmaPhoneCallState.getCurrentCallState();
-        CdmaPhoneCallState.PhoneCallState prevCdmaCallState =
-                app.cdmaPhoneCallState.getPreviousCallState();
-
-        if ((prevCdmaCallState == CdmaPhoneCallState.PhoneCallState.THRWAY_ACTIVE)
-                && (currCdmaCallState == CdmaPhoneCallState.PhoneCallState.CONF_CALL)) {
-            // If the current state is reached after merging two calls
-            // we set the state of all the connections as ACTIVE
-            state = 0;
-        } else {
-            switch (c.getState()) {
-            case ACTIVE:
-                // For CDMA since both the connections are set as active by FW after accepting
-                // a Call waiting or making a 3 way call, we need to set the state specifically
-                // to ACTIVE/HOLDING based on the mCdmaIsSecondCallActive flag. This way the
-                // CLCC result will allow BT devices to enable the swap or merge options
-                if (index == 0) { // For the 1st active connection
-                    state = mCdmaIsSecondCallActive ? 1 : 0;
-                } else { // for the 2nd active connection
-                    state = mCdmaIsSecondCallActive ? 0 : 1;
-                }
-                break;
-            case HOLDING:
-                state = 1;
-                break;
-            case DIALING:
-                state = 2;
-                break;
-            case ALERTING:
-                state = 3;
-                break;
-            case INCOMING:
-                state = 4;
-                break;
-            case WAITING:
-                state = 5;
-                break;
-            default:
-                return null;  // bad state
-            }
-        }
-
-        int mpty = 0;
-        if (currCdmaCallState == CdmaPhoneCallState.PhoneCallState.CONF_CALL) {
-            if (prevCdmaCallState == CdmaPhoneCallState.PhoneCallState.THRWAY_ACTIVE) {
-                // If the current state is reached after merging two calls
-                // we set the multiparty call true.
-                mpty = 1;
-            } else {
-                // CALL_CONF state is not from merging two calls, but from
-                // accepting the second call. In this case first will be on
-                // hold in most cases but in some cases its already merged.
-                // However, we will follow the common case and the test case
-                // as per Bluetooth SIG PTS
-                mpty = 0;
-            }
-        } else {
-            mpty = 0;
-        }
-
-        int direction = c.isIncoming() ? 1 : 0;
-
-        String number = c.getAddress();
-        int type = -1;
-        if (number != null) {
-            type = PhoneNumberUtils.toaFromString(number);
-        }
-
-        String result = "+CLCC: " + (index + 1) + "," + direction + "," + state + ",0," + mpty;
-        if (number != null) {
-            result += ",\"" + number + "\"," + type;
-        }
-        return result;
-    }
-
-    /*
-     * Register a vendor-specific command.
-     * @param commandName the name of the command.  For example, if the expected
-     * incoming command is <code>AT+FOO=bar,baz</code>, the value of this should be
-     * <code>"+FOO"</code>.
-     * @param companyId the Bluetooth SIG Company Identifier
-     * @param parser the AtParser on which to register the command
-     */
-    private void registerVendorSpecificCommand(String commandName,
-                                               int companyId,
-                                               AtParser parser) {
-        parser.register(commandName,
-                        new VendorSpecificCommandHandler(commandName, companyId));
-    }
-
-    /*
-     * Register all vendor-specific commands here.
-     */
-    private void registerAllVendorSpecificCommands() {
-        AtParser parser = mHeadset.getAtParser();
-
-        // Plantronics-specific headset events go here
-        registerVendorSpecificCommand("+XEVENT",
-                                      BluetoothAssignedNumbers.PLANTRONICS,
-                                      parser);
-    }
-
-    /**
-     * Register AT Command handlers to implement the Headset profile
-     */
-    private void initializeHeadsetAtParser() {
-        if (VDBG) log("Registering Headset AT commands");
-        AtParser parser = mHeadset.getAtParser();
-        // Headsets usually only have one button, which is meant to cause the
-        // HS to send us AT+CKPD=200 or AT+CKPD.
-        parser.register("+CKPD", new AtCommandHandler() {
-            private AtCommandResult headsetButtonPress() {
-                if (mCM.getFirstActiveRingingCall().isRinging()) {
-                    // Answer the call
-                    mBluetoothPhoneState.stopRing();
-                    sendURC("OK");
-                    PhoneUtils.answerCall(mCM.getFirstActiveRingingCall());
-                    // If in-band ring tone is supported, SCO connection will already
-                    // be up and the following call will just return.
-                    audioOn();
-                    return new AtCommandResult(AtCommandResult.UNSOLICITED);
-                } else if (mCM.hasActiveFgCall()) {
-                    if (!isAudioOn()) {
-                        // Transfer audio from AG to HS
-                        audioOn();
-                    } else {
-                        if (mHeadset.getDirection() == HeadsetBase.DIRECTION_INCOMING &&
-                          (System.currentTimeMillis() - mHeadset.getConnectTimestamp()) < 5000) {
-                            // Headset made a recent ACL connection to us - and
-                            // made a mandatory AT+CKPD request to connect
-                            // audio which races with our automatic audio
-                            // setup.  ignore
-                        } else {
-                            // Hang up the call
-                            audioOff();
-                            PhoneUtils.hangup(PhoneApp.getInstance().mCM);
-                        }
-                    }
-                    return new AtCommandResult(AtCommandResult.OK);
-                } else {
-                    // No current call - redial last number
-                    return redial();
-                }
-            }
-            @Override
-            public AtCommandResult handleActionCommand() {
-                return headsetButtonPress();
-            }
-            @Override
-            public AtCommandResult handleSetCommand(Object[] args) {
-                return headsetButtonPress();
-            }
-        });
-    }
-
-    /**
-     * Register AT Command handlers to implement the Handsfree profile
-     */
-    private void initializeHandsfreeAtParser() {
-        if (VDBG) log("Registering Handsfree AT commands");
-        AtParser parser = mHeadset.getAtParser();
-        final Phone phone = mCM.getDefaultPhone();
-
-        // Answer
-        parser.register('A', new AtCommandHandler() {
-            @Override
-            public AtCommandResult handleBasicCommand(String args) {
-                sendURC("OK");
-                mBluetoothPhoneState.stopRing();
-                PhoneUtils.answerCall(mCM.getFirstActiveRingingCall());
-                return new AtCommandResult(AtCommandResult.UNSOLICITED);
-            }
-        });
-        parser.register('D', new AtCommandHandler() {
-            @Override
-            public AtCommandResult handleBasicCommand(String args) {
-                if (args.length() > 0) {
-                    if (args.charAt(0) == '>') {
-                        // Yuck - memory dialling requested.
-                        // Just dial last number for now
-                        if (args.startsWith(">9999")) {   // for PTS test
-                            return new AtCommandResult(AtCommandResult.ERROR);
-                        }
-                        return redial();
-                    } else {
-                        // Send terminateScoUsingVirtualVoiceCall
-                        terminateScoUsingVirtualVoiceCall();
-                        // Remove trailing ';'
-                        if (args.charAt(args.length() - 1) == ';') {
-                            args = args.substring(0, args.length() - 1);
-                        }
-
-                        args = PhoneNumberUtils.convertPreDial(args);
-
-                        Intent intent = new Intent(Intent.ACTION_CALL_PRIVILEGED,
-                                Uri.fromParts(Constants.SCHEME_TEL, args, null));
-                        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-                        mContext.startActivity(intent);
-
-                        expectCallStart();
-                        return new AtCommandResult(AtCommandResult.UNSOLICITED);  // send nothing
-                    }
-                }
-                return new AtCommandResult(AtCommandResult.ERROR);
-            }
-        });
-
-        // Hang-up command
-        parser.register("+CHUP", new AtCommandHandler() {
-            @Override
-            public AtCommandResult handleActionCommand() {
-                sendURC("OK");
-                if (isVirtualCallInProgress()) {
-                    terminateScoUsingVirtualVoiceCall();
-                } else {
-                    if (mCM.hasActiveFgCall()) {
-                        PhoneUtils.hangupActiveCall(mCM.getActiveFgCall());
-                    } else if (mCM.hasActiveRingingCall()) {
-                        PhoneUtils.hangupRingingCall(mCM.getFirstActiveRingingCall());
-                    } else if (mCM.hasActiveBgCall()) {
-                        PhoneUtils.hangupHoldingCall(mCM.getFirstActiveBgCall());
-                    }
-                }
-                return new AtCommandResult(AtCommandResult.UNSOLICITED);
-            }
-        });
-
-        // Bluetooth Retrieve Supported Features command
-        parser.register("+BRSF", new AtCommandHandler() {
-            private AtCommandResult sendBRSF() {
-                return new AtCommandResult("+BRSF: " + mLocalBrsf);
-            }
-            @Override
-            public AtCommandResult handleSetCommand(Object[] args) {
-                // AT+BRSF=<handsfree supported features bitmap>
-                // Handsfree is telling us which features it supports. We
-                // send the features we support
-                if (args.length == 1 && (args[0] instanceof Integer)) {
-                    mRemoteBrsf = (Integer) args[0];
-                } else {
-                    Log.w(TAG, "HF didn't sent BRSF assuming 0");
-                }
-                return sendBRSF();
-            }
-            @Override
-            public AtCommandResult handleActionCommand() {
-                // This seems to be out of spec, but lets do the nice thing
-                return sendBRSF();
-            }
-            @Override
-            public AtCommandResult handleReadCommand() {
-                // This seems to be out of spec, but lets do the nice thing
-                return sendBRSF();
-            }
-        });
-
-        // Call waiting notification on/off
-        parser.register("+CCWA", new AtCommandHandler() {
-            @Override
-            public AtCommandResult handleActionCommand() {
-                // Seems to be out of spec, but lets return nicely
-                return new AtCommandResult(AtCommandResult.OK);
-            }
-            @Override
-            public AtCommandResult handleReadCommand() {
-                // Call waiting is always on
-                return new AtCommandResult("+CCWA: 1");
-            }
-            @Override
-            public AtCommandResult handleSetCommand(Object[] args) {
-                // AT+CCWA=<n>
-                // Handsfree is trying to enable/disable call waiting. We
-                // cannot disable in the current implementation.
-                return new AtCommandResult(AtCommandResult.OK);
-            }
-            @Override
-            public AtCommandResult handleTestCommand() {
-                // Request for range of supported CCWA paramters
-                return new AtCommandResult("+CCWA: (\"n\",(1))");
-            }
-        });
-
-        // Mobile Equipment Event Reporting enable/disable command
-        // Of the full 3GPP syntax paramters (mode, keyp, disp, ind, bfr) we
-        // only support paramter ind (disable/enable evert reporting using
-        // +CDEV)
-        parser.register("+CMER", new AtCommandHandler() {
-            @Override
-            public AtCommandResult handleReadCommand() {
-                return new AtCommandResult(
-                        "+CMER: 3,0,0," + (mIndicatorsEnabled ? "1" : "0"));
-            }
-            @Override
-            public AtCommandResult handleSetCommand(Object[] args) {
-                if (args.length < 4) {
-                    // This is a syntax error
-                    return new AtCommandResult(AtCommandResult.ERROR);
-                } else if (args[0].equals(3) && args[1].equals(0) &&
-                           args[2].equals(0)) {
-                    boolean valid = false;
-                    if (args[3].equals(0)) {
-                        mIndicatorsEnabled = false;
-                        valid = true;
-                    } else if (args[3].equals(1)) {
-                        mIndicatorsEnabled = true;
-                        valid = true;
-                    }
-                    if (valid) {
-                        if ((mRemoteBrsf & BRSF_HF_CW_THREE_WAY_CALLING) == 0x0) {
-                            mServiceConnectionEstablished = true;
-                            sendURC("OK");  // send immediately, then initiate audio
-                            if (isIncallAudio()) {
-                                audioOn();
-                            } else if (mCM.getFirstActiveRingingCall().isRinging()) {
-                                // need to update HS with RING cmd when single
-                                // ringing call exist
-                                mBluetoothPhoneState.ring();
-                            }
-                            // only send OK once
-                            return new AtCommandResult(AtCommandResult.UNSOLICITED);
-                        } else {
-                            return new AtCommandResult(AtCommandResult.OK);
-                        }
-                    }
-                }
-                return reportCmeError(BluetoothCmeError.OPERATION_NOT_SUPPORTED);
-            }
-            @Override
-            public AtCommandResult handleTestCommand() {
-                return new AtCommandResult("+CMER: (3),(0),(0),(0-1)");
-            }
-        });
-
-        // Mobile Equipment Error Reporting enable/disable
-        parser.register("+CMEE", new AtCommandHandler() {
-            @Override
-            public AtCommandResult handleActionCommand() {
-                // out of spec, assume they want to enable
-                mCmee = true;
-                return new AtCommandResult(AtCommandResult.OK);
-            }
-            @Override
-            public AtCommandResult handleReadCommand() {
-                return new AtCommandResult("+CMEE: " + (mCmee ? "1" : "0"));
-            }
-            @Override
-            public AtCommandResult handleSetCommand(Object[] args) {
-                // AT+CMEE=<n>
-                if (args.length == 0) {
-                    // <n> ommitted - default to 0
-                    mCmee = false;
-                    return new AtCommandResult(AtCommandResult.OK);
-                } else if (!(args[0] instanceof Integer)) {
-                    // Syntax error
-                    return new AtCommandResult(AtCommandResult.ERROR);
-                } else {
-                    mCmee = ((Integer)args[0] == 1);
-                    return new AtCommandResult(AtCommandResult.OK);
-                }
-            }
-            @Override
-            public AtCommandResult handleTestCommand() {
-                // Probably not required but spec, but no harm done
-                return new AtCommandResult("+CMEE: (0-1)");
-            }
-        });
-
-        // Bluetooth Last Dialled Number
-        parser.register("+BLDN", new AtCommandHandler() {
-            @Override
-            public AtCommandResult handleActionCommand() {
-                return redial();
-            }
-        });
-
-        // Indicator Update command
-        parser.register("+CIND", new AtCommandHandler() {
-            @Override
-            public AtCommandResult handleReadCommand() {
-                return mBluetoothPhoneState.toCindResult();
-            }
-            @Override
-            public AtCommandResult handleTestCommand() {
-                return mBluetoothPhoneState.getCindTestResult();
-            }
-        });
-
-        // Query Signal Quality (legacy)
-        parser.register("+CSQ", new AtCommandHandler() {
-            @Override
-            public AtCommandResult handleActionCommand() {
-                return mBluetoothPhoneState.toCsqResult();
-            }
-        });
-
-        // Query network registration state
-        parser.register("+CREG", new AtCommandHandler() {
-            @Override
-            public AtCommandResult handleReadCommand() {
-                return new AtCommandResult(mBluetoothPhoneState.toCregString());
-            }
-        });
-
-        // Send DTMF. I don't know if we are also expected to play the DTMF tone
-        // locally, right now we don't
-        parser.register("+VTS", new AtCommandHandler() {
-            @Override
-            public AtCommandResult handleSetCommand(Object[] args) {
-                if (args.length >= 1) {
-                    char c;
-                    if (args[0] instanceof Integer) {
-                        c = ((Integer) args[0]).toString().charAt(0);
-                    } else {
-                        c = ((String) args[0]).charAt(0);
-                    }
-                    if (isValidDtmf(c)) {
-                        phone.sendDtmf(c);
-                        return new AtCommandResult(AtCommandResult.OK);
-                    }
-                }
-                return new AtCommandResult(AtCommandResult.ERROR);
-            }
-            private boolean isValidDtmf(char c) {
-                switch (c) {
-                case '#':
-                case '*':
-                    return true;
-                default:
-                    if (Character.digit(c, 14) != -1) {
-                        return true;  // 0-9 and A-D
-                    }
-                    return false;
-                }
-            }
-        });
-
-        // List calls
-        parser.register("+CLCC", new AtCommandHandler() {
-            @Override
-            public AtCommandResult handleActionCommand() {
-                int phoneType = phone.getPhoneType();
-                // Handsfree carkits expect that +CLCC is properly responded to.
-                // Hence we ensure that a proper response is sent for the virtual call too.
-                if (isVirtualCallInProgress()) {
-                    String number = phone.getLine1Number();
-                    AtCommandResult result = new AtCommandResult(AtCommandResult.OK);
-                    String args;
-                    if (number == null) {
-                        args = "+CLCC: 1,0,0,0,0,\"\",0";
-                    }
-                    else
-                    {
-                        args = "+CLCC: 1,0,0,0,0,\"" + number + "\"," +
-                                  PhoneNumberUtils.toaFromString(number);
-                    }
-                    result.addResponse(args);
-                    return result;
-                }
-                if (phoneType == PhoneConstants.PHONE_TYPE_CDMA) {
-                    return cdmaGetClccResult();
-                } else if (phoneType == PhoneConstants.PHONE_TYPE_GSM) {
-                    return gsmGetClccResult();
-                } else {
-                    throw new IllegalStateException("Unexpected phone type: " + phoneType);
-                }
-            }
-        });
-
-        // Call Hold and Multiparty Handling command
-        parser.register("+CHLD", new AtCommandHandler() {
-            @Override
-            public AtCommandResult handleSetCommand(Object[] args) {
-                int phoneType = phone.getPhoneType();
-                Call ringingCall = mCM.getFirstActiveRingingCall();
-                Call backgroundCall = mCM.getFirstActiveBgCall();
-
-                if (args.length >= 1) {
-                    if (args[0].equals(0)) {
-                        boolean result;
-                        if (ringingCall.isRinging()) {
-                            result = PhoneUtils.hangupRingingCall(ringingCall);
-                        } else {
-                            result = PhoneUtils.hangupHoldingCall(backgroundCall);
-                        }
-                        if (result) {
-                            return new AtCommandResult(AtCommandResult.OK);
-                        } else {
-                            return new AtCommandResult(AtCommandResult.ERROR);
-                        }
-                    } else if (args[0].equals(1)) {
-                        if (phoneType == PhoneConstants.PHONE_TYPE_CDMA) {
-                            if (ringingCall.isRinging()) {
-                                // Hangup the active call and then answer call waiting call.
-                                if (VDBG) log("CHLD:1 Callwaiting Answer call");
-                                PhoneUtils.hangupRingingAndActive(phone);
-                            } else {
-                                // If there is no Call waiting then just hangup
-                                // the active call. In CDMA this mean that the complete
-                                // call session would be ended
-                                if (VDBG) log("CHLD:1 Hangup Call");
-                                PhoneUtils.hangup(PhoneApp.getInstance().mCM);
-                            }
-                            return new AtCommandResult(AtCommandResult.OK);
-                        } else if (phoneType == PhoneConstants.PHONE_TYPE_GSM) {
-                            // Hangup active call, answer held call
-                            if (PhoneUtils.answerAndEndActive(
-                                    PhoneApp.getInstance().mCM, ringingCall)) {
-                                return new AtCommandResult(AtCommandResult.OK);
-                            } else {
-                                return new AtCommandResult(AtCommandResult.ERROR);
-                            }
-                        } else {
-                            throw new IllegalStateException("Unexpected phone type: " + phoneType);
-                        }
-                    } else if (args[0].equals(2)) {
-                        sendURC("OK");
-                        if (phoneType == PhoneConstants.PHONE_TYPE_CDMA) {
-                            // For CDMA, the way we switch to a new incoming call is by
-                            // calling PhoneUtils.answerCall(). switchAndHoldActive() won't
-                            // properly update the call state within telephony.
-                            // If the Phone state is already in CONF_CALL then we simply send
-                            // a flash cmd by calling switchHoldingAndActive()
-                            if (ringingCall.isRinging()) {
-                                if (VDBG) log("CHLD:2 Callwaiting Answer call");
-                                PhoneUtils.answerCall(ringingCall);
-                                PhoneUtils.setMute(false);
-                                // Setting the second callers state flag to TRUE (i.e. active)
-                                cdmaSetSecondCallState(true);
-                            } else if (PhoneApp.getInstance().cdmaPhoneCallState
-                                    .getCurrentCallState()
-                                    == CdmaPhoneCallState.PhoneCallState.CONF_CALL) {
-                                if (VDBG) log("CHLD:2 Swap Calls");
-                                PhoneUtils.switchHoldingAndActive(backgroundCall);
-                                // Toggle the second callers active state flag
-                                cdmaSwapSecondCallState();
-                            }
-                        } else if (phoneType == PhoneConstants.PHONE_TYPE_GSM) {
-                            PhoneUtils.switchHoldingAndActive(backgroundCall);
-                        } else {
-                            throw new IllegalStateException("Unexpected phone type: " + phoneType);
-                        }
-                        return new AtCommandResult(AtCommandResult.UNSOLICITED);
-                    } else if (args[0].equals(3)) {
-                        sendURC("OK");
-                        if (phoneType == PhoneConstants.PHONE_TYPE_CDMA) {
-                            CdmaPhoneCallState.PhoneCallState state =
-                                PhoneApp.getInstance().cdmaPhoneCallState.getCurrentCallState();
-                            // For CDMA, we need to check if the call is in THRWAY_ACTIVE state
-                            if (state == CdmaPhoneCallState.PhoneCallState.THRWAY_ACTIVE) {
-                                if (VDBG) log("CHLD:3 Merge Calls");
-                                PhoneUtils.mergeCalls();
-                            } else if (state == CdmaPhoneCallState.PhoneCallState.CONF_CALL) {
-                                // State is CONF_CALL already and we are getting a merge call
-                                // This can happen when CONF_CALL was entered from a Call Waiting
-                                mBluetoothPhoneState.updateCallHeld();
-                            }
-                        } else if (phoneType == PhoneConstants.PHONE_TYPE_GSM) {
-                            if (mCM.hasActiveFgCall() && mCM.hasActiveBgCall()) {
-                                PhoneUtils.mergeCalls();
-                            }
-                        } else {
-                            throw new IllegalStateException("Unexpected phone type: " + phoneType);
-                        }
-                        return new AtCommandResult(AtCommandResult.UNSOLICITED);
-                    }
-                }
-                return new AtCommandResult(AtCommandResult.ERROR);
-            }
-            @Override
-            public AtCommandResult handleTestCommand() {
-                mServiceConnectionEstablished = true;
-                sendURC("+CHLD: (0,1,2,3)");
-                sendURC("OK");  // send reply first, then connect audio
-                if (isIncallAudio()) {
-                    audioOn();
-                } else if (mCM.getFirstActiveRingingCall().isRinging()) {
-                    // need to update HS with RING when single ringing call exist
-                    mBluetoothPhoneState.ring();
-                }
-                // already replied
-                return new AtCommandResult(AtCommandResult.UNSOLICITED);
-            }
-        });
-
-        // Get Network operator name
-        parser.register("+COPS", new AtCommandHandler() {
-            @Override
-            public AtCommandResult handleReadCommand() {
-                String operatorName = phone.getServiceState().getOperatorAlphaLong();
-                if (operatorName != null) {
-                    if (operatorName.length() > 16) {
-                        operatorName = operatorName.substring(0, 16);
-                    }
-                    return new AtCommandResult(
-                            "+COPS: 0,0,\"" + operatorName + "\"");
-                } else {
-                    return new AtCommandResult(
-                            "+COPS: 0");
-                }
-            }
-            @Override
-            public AtCommandResult handleSetCommand(Object[] args) {
-                // Handsfree only supports AT+COPS=3,0
-                if (args.length != 2 || !(args[0] instanceof Integer)
-                    || !(args[1] instanceof Integer)) {
-                    // syntax error
-                    return new AtCommandResult(AtCommandResult.ERROR);
-                } else if ((Integer)args[0] != 3 || (Integer)args[1] != 0) {
-                    return reportCmeError(BluetoothCmeError.OPERATION_NOT_SUPPORTED);
-                } else {
-                    return new AtCommandResult(AtCommandResult.OK);
-                }
-            }
-            @Override
-            public AtCommandResult handleTestCommand() {
-                // Out of spec, but lets be friendly
-                return new AtCommandResult("+COPS: (3),(0)");
-            }
-        });
-
-        // Mobile PIN
-        // AT+CPIN is not in the handsfree spec (although it is in 3GPP)
-        parser.register("+CPIN", new AtCommandHandler() {
-            @Override
-            public AtCommandResult handleReadCommand() {
-                return new AtCommandResult("+CPIN: READY");
-            }
-        });
-
-        // Bluetooth Response and Hold
-        // Only supported on PDC (Japan) and CDMA networks.
-        parser.register("+BTRH", new AtCommandHandler() {
-            @Override
-            public AtCommandResult handleReadCommand() {
-                // Replying with just OK indicates no response and hold
-                // features in use now
-                return new AtCommandResult(AtCommandResult.OK);
-            }
-            @Override
-            public AtCommandResult handleSetCommand(Object[] args) {
-                // Neeed PDC or CDMA
-                return new AtCommandResult(AtCommandResult.ERROR);
-            }
-        });
-
-        // Request International Mobile Subscriber Identity (IMSI)
-        // Not in bluetooth handset spec
-        parser.register("+CIMI", new AtCommandHandler() {
-            @Override
-            public AtCommandResult handleActionCommand() {
-                // AT+CIMI
-                String imsi = phone.getSubscriberId();
-                if (imsi == null || imsi.length() == 0) {
-                    return reportCmeError(BluetoothCmeError.SIM_FAILURE);
-                } else {
-                    return new AtCommandResult(imsi);
-                }
-            }
-        });
-
-        // Calling Line Identification Presentation
-        parser.register("+CLIP", new AtCommandHandler() {
-            @Override
-            public AtCommandResult handleReadCommand() {
-                // Currently assumes the network is provisioned for CLIP
-                return new AtCommandResult("+CLIP: " + (mClip ? "1" : "0") + ",1");
-            }
-            @Override
-            public AtCommandResult handleSetCommand(Object[] args) {
-                // AT+CLIP=<n>
-                if (args.length >= 1 && (args[0].equals(0) || args[0].equals(1))) {
-                    mClip = args[0].equals(1);
-                    return new AtCommandResult(AtCommandResult.OK);
-                } else {
-                    return new AtCommandResult(AtCommandResult.ERROR);
-                }
-            }
-            @Override
-            public AtCommandResult handleTestCommand() {
-                return new AtCommandResult("+CLIP: (0-1)");
-            }
-        });
-
-        // AT+CGSN - Returns the device IMEI number.
-        parser.register("+CGSN", new AtCommandHandler() {
-            @Override
-            public AtCommandResult handleActionCommand() {
-                // Get the IMEI of the device.
-                // phone will not be NULL at this point.
-                return new AtCommandResult("+CGSN: " + phone.getDeviceId());
-            }
-        });
-
-        // AT+CGMM - Query Model Information
-        parser.register("+CGMM", new AtCommandHandler() {
-            @Override
-            public AtCommandResult handleActionCommand() {
-                // Return the Model Information.
-                String model = SystemProperties.get("ro.product.model");
-                if (model != null) {
-                    return new AtCommandResult("+CGMM: " + model);
-                } else {
-                    return new AtCommandResult(AtCommandResult.ERROR);
-                }
-            }
-        });
-
-        // AT+CGMI - Query Manufacturer Information
-        parser.register("+CGMI", new AtCommandHandler() {
-            @Override
-            public AtCommandResult handleActionCommand() {
-                // Return the Model Information.
-                String manuf = SystemProperties.get("ro.product.manufacturer");
-                if (manuf != null) {
-                    return new AtCommandResult("+CGMI: " + manuf);
-                } else {
-                    return new AtCommandResult(AtCommandResult.ERROR);
-                }
-            }
-        });
-
-        // Noise Reduction and Echo Cancellation control
-        parser.register("+NREC", new AtCommandHandler() {
-            @Override
-            public AtCommandResult handleSetCommand(Object[] args) {
-                if (args[0].equals(0)) {
-                    mAudioManager.setParameters(HEADSET_NREC+"=off");
-                    return new AtCommandResult(AtCommandResult.OK);
-                } else if (args[0].equals(1)) {
-                    mAudioManager.setParameters(HEADSET_NREC+"=on");
-                    return new AtCommandResult(AtCommandResult.OK);
-                }
-                return new AtCommandResult(AtCommandResult.ERROR);
-            }
-        });
-
-        // Voice recognition (dialing)
-        parser.register("+BVRA", new AtCommandHandler() {
-            @Override
-            public AtCommandResult handleSetCommand(Object[] args) {
-                if (!BluetoothHeadset.isBluetoothVoiceDialingEnabled(mContext)) {
-                    return new AtCommandResult(AtCommandResult.ERROR);
-                }
-                if (args.length >= 1 && args[0].equals(1)) {
-                    synchronized (BluetoothHandsfree.this) {
-                        if (!isVoiceRecognitionInProgress() &&
-                            !isCellularCallInProgress() &&
-                            !isVirtualCallInProgress()) {
-                            try {
-                                mContext.startActivity(sVoiceCommandIntent);
-                            } catch (ActivityNotFoundException e) {
-                                return new AtCommandResult(AtCommandResult.ERROR);
-                            }
-                            expectVoiceRecognition();
-                        }
-                    }
-                    return new AtCommandResult(AtCommandResult.UNSOLICITED);  // send nothing yet
-                } else if (args.length >= 1 && args[0].equals(0)) {
-                    if (isVoiceRecognitionInProgress()) {
-                        audioOff();
-                    }
-                    return new AtCommandResult(AtCommandResult.OK);
-                }
-                return new AtCommandResult(AtCommandResult.ERROR);
-            }
-            @Override
-            public AtCommandResult handleTestCommand() {
-                return new AtCommandResult("+BVRA: (0-1)");
-            }
-        });
-
-        // Retrieve Subscriber Number
-        parser.register("+CNUM", new AtCommandHandler() {
-            @Override
-            public AtCommandResult handleActionCommand() {
-                String number = phone.getLine1Number();
-                if (number == null) {
-                    return new AtCommandResult(AtCommandResult.OK);
-                }
-                return new AtCommandResult("+CNUM: ,\"" + number + "\"," +
-                        PhoneNumberUtils.toaFromString(number) + ",,4");
-            }
-        });
-
-        // Microphone Gain
-        parser.register("+VGM", new AtCommandHandler() {
-            @Override
-            public AtCommandResult handleSetCommand(Object[] args) {
-                // AT+VGM=<gain>    in range [0,15]
-                // Headset/Handsfree is reporting its current gain setting
-                return new AtCommandResult(AtCommandResult.OK);
-            }
-        });
-
-        // Speaker Gain
-        parser.register("+VGS", new AtCommandHandler() {
-            @Override
-            public AtCommandResult handleSetCommand(Object[] args) {
-                // AT+VGS=<gain>    in range [0,15]
-                if (args.length != 1 || !(args[0] instanceof Integer)) {
-                    return new AtCommandResult(AtCommandResult.ERROR);
-                }
-                mScoGain = (Integer) args[0];
-                int flag =  mAudioManager.isBluetoothScoOn() ? AudioManager.FLAG_SHOW_UI:0;
-
-                mAudioManager.setStreamVolume(AudioManager.STREAM_BLUETOOTH_SCO, mScoGain, flag);
-                return new AtCommandResult(AtCommandResult.OK);
-            }
-        });
-
-        // Phone activity status
-        parser.register("+CPAS", new AtCommandHandler() {
-            @Override
-            public AtCommandResult handleActionCommand() {
-                int status = 0;
-                switch (mCM.getState()) {
-                case IDLE:
-                    status = 0;
-                    break;
-                case RINGING:
-                    status = 3;
-                    break;
-                case OFFHOOK:
-                    status = 4;
-                    break;
-                }
-                return new AtCommandResult("+CPAS: " + status);
-            }
-        });
-
-        mPhonebook.register(parser);
-    }
-
-    public void sendScoGainUpdate(int gain) {
-        if (mScoGain != gain && (mRemoteBrsf & BRSF_HF_REMOTE_VOL_CONTROL) != 0x0) {
-            sendURC("+VGS:" + gain);
-            mScoGain = gain;
-        }
-    }
-
-    public AtCommandResult reportCmeError(int error) {
-        if (mCmee) {
-            AtCommandResult result = new AtCommandResult(AtCommandResult.UNSOLICITED);
-            result.addResponse("+CME ERROR: " + error);
-            return result;
-        } else {
-            return new AtCommandResult(AtCommandResult.ERROR);
-        }
-    }
-
-    private static final int START_CALL_TIMEOUT = 10000;  // ms
-
-    private synchronized void expectCallStart() {
-        mWaitingForCallStart = true;
-        Message msg = Message.obtain(mHandler, CHECK_CALL_STARTED);
-        mHandler.sendMessageDelayed(msg, START_CALL_TIMEOUT);
-        if (!mStartCallWakeLock.isHeld()) {
-            mStartCallWakeLock.acquire(START_CALL_TIMEOUT);
-        }
-    }
-
-    private synchronized void callStarted() {
-        if (mWaitingForCallStart) {
-            mWaitingForCallStart = false;
-            sendURC("OK");
-            if (mStartCallWakeLock.isHeld()) {
-                mStartCallWakeLock.release();
-            }
-        }
-    }
-
-    private static final int START_VOICE_RECOGNITION_TIMEOUT = 5000;  // ms
-
-    private synchronized void expectVoiceRecognition() {
-        mWaitingForVoiceRecognition = true;
-        Message msg = Message.obtain(mHandler, CHECK_VOICE_RECOGNITION_STARTED);
-        mHandler.sendMessageDelayed(msg, START_VOICE_RECOGNITION_TIMEOUT);
-        if (!mStartVoiceRecognitionWakeLock.isHeld()) {
-            mStartVoiceRecognitionWakeLock.acquire(START_VOICE_RECOGNITION_TIMEOUT);
-        }
-    }
-
-    /* package */ synchronized boolean startVoiceRecognition() {
-
-        if  ((isCellularCallInProgress()) ||
-             (isVirtualCallInProgress()) ||
-             mVoiceRecognitionStarted) {
-            Log.e(TAG, "startVoiceRecognition: Call in progress");
-            return false;
-        }
-
-        mVoiceRecognitionStarted = true;
-
-        if (mWaitingForVoiceRecognition) {
-            // HF initiated
-            mWaitingForVoiceRecognition = false;
-            sendURC("OK");
-        } else {
-            // AG initiated
-            sendURC("+BVRA: 1");
-        }
-        boolean ret = audioOn();
-        if (ret == false) {
-            mVoiceRecognitionStarted = false;
-        }
-        if (mStartVoiceRecognitionWakeLock.isHeld()) {
-            mStartVoiceRecognitionWakeLock.release();
-        }
-        return ret;
-    }
-
-    /* package */ synchronized boolean stopVoiceRecognition() {
-
-        if (!isVoiceRecognitionInProgress()) {
-            return false;
-        }
-
-        mVoiceRecognitionStarted = false;
-
-        sendURC("+BVRA: 0");
-        audioOff();
-        return true;
-    }
-
-    // Voice Recognition in Progress
-    private boolean isVoiceRecognitionInProgress() {
-        return (mVoiceRecognitionStarted || mWaitingForVoiceRecognition);
-    }
-
-    /*
-     * This class broadcasts vendor-specific commands + arguments to interested receivers.
-     */
-    private class VendorSpecificCommandHandler extends AtCommandHandler {
-
-        private String mCommandName;
-
-        private int mCompanyId;
-
-        private VendorSpecificCommandHandler(String commandName, int companyId) {
-            mCommandName = commandName;
-            mCompanyId = companyId;
-        }
-
-        @Override
-        public AtCommandResult handleReadCommand() {
-            return new AtCommandResult(AtCommandResult.ERROR);
-        }
-
-        @Override
-        public AtCommandResult handleTestCommand() {
-            return new AtCommandResult(AtCommandResult.ERROR);
-        }
-
-        @Override
-        public AtCommandResult handleActionCommand() {
-            return new AtCommandResult(AtCommandResult.ERROR);
-        }
-
-        @Override
-        public AtCommandResult handleSetCommand(Object[] arguments) {
-            broadcastVendorSpecificEventIntent(mCommandName,
-                                               mCompanyId,
-                                               BluetoothHeadset.AT_CMD_TYPE_SET,
-                                               arguments,
-                                               mHeadset.getRemoteDevice());
-            return new AtCommandResult(AtCommandResult.OK);
-        }
-    }
-
-    private boolean inDebug() {
-        return DBG && SystemProperties.getBoolean(DebugThread.DEBUG_HANDSFREE, false);
-    }
-
-    private boolean allowAudioAnytime() {
-        return inDebug() && SystemProperties.getBoolean(DebugThread.DEBUG_HANDSFREE_AUDIO_ANYTIME,
-                false);
-    }
-
-    private void startDebug() {
-        if (DBG && mDebugThread == null) {
-            mDebugThread = new DebugThread();
-            mDebugThread.start();
-        }
-    }
-
-    private void stopDebug() {
-        if (mDebugThread != null) {
-            mDebugThread.interrupt();
-            mDebugThread = null;
-        }
-    }
-
-    // VirtualCall SCO support
-    //
-
-    // Cellular call in progress
-    private boolean isCellularCallInProgress() {
-        if (mCM.hasActiveFgCall() || mCM.hasActiveRingingCall()) return true;
-        return false;
-    }
-
-    // Virtual Call in Progress
-    private boolean isVirtualCallInProgress() {
-        return mVirtualCallStarted;
-    }
-
-    void setVirtualCallInProgress(boolean state) {
-        mVirtualCallStarted = state;
-    }
-
-    //NOTE: Currently the VirtualCall API does not allow the application to initiate a call
-    // transfer. Call transfer may be initiated from the handsfree device and this is handled by
-    // the VirtualCall API
-    synchronized boolean initiateScoUsingVirtualVoiceCall() {
-        if (DBG) log("initiateScoUsingVirtualVoiceCall: Received");
-        // 1. Check if the SCO state is idle
-        if (isCellularCallInProgress() || isVoiceRecognitionInProgress()) {
-            Log.e(TAG, "initiateScoUsingVirtualVoiceCall: Call in progress");
-            return false;
-        }
-
-        // 2. Perform outgoing call setup procedure
-        if (mBluetoothPhoneState.sendUpdate() && !isVirtualCallInProgress()) {
-            AtCommandResult result = new AtCommandResult(AtCommandResult.UNSOLICITED);
-            // outgoing call
-            result.addResponse("+CIEV: 3,2");
-            result.addResponse("+CIEV: 2,1");
-            result.addResponse("+CIEV: 3,0");
-            sendURC(result.toString());
-            if (DBG) Log.d(TAG, "initiateScoUsingVirtualVoiceCall: Sent Call-setup procedure");
-        }
-
-        mVirtualCallStarted = true;
-
-        // 3. Open the Audio Connection
-        if (audioOn() == false) {
-            log("initiateScoUsingVirtualVoiceCall: audioON failed");
-            terminateScoUsingVirtualVoiceCall();
-            return false;
-        }
-
-        mAudioPossible = true;
-
-        // Done
-        if (DBG) log("initiateScoUsingVirtualVoiceCall: Done");
-        return true;
-    }
-
-    synchronized boolean terminateScoUsingVirtualVoiceCall() {
-        if (DBG) log("terminateScoUsingVirtualVoiceCall: Received");
-
-        if (!isVirtualCallInProgress()) {
-            return false;
-        }
-
-        // 1. Release audio connection
-        audioOff();
-
-        // 2. terminate call-setup
-        if (mBluetoothPhoneState.sendUpdate()) {
-            AtCommandResult result = new AtCommandResult(AtCommandResult.UNSOLICITED);
-            // outgoing call
-            result.addResponse("+CIEV: 2,0");
-            sendURC(result.toString());
-            if (DBG) log("terminateScoUsingVirtualVoiceCall: Sent Call-setup procedure");
-        }
-        mVirtualCallStarted = false;
-        mAudioPossible = false;
-
-        // Done
-        if (DBG) log("terminateScoUsingVirtualVoiceCall: Done");
-        return true;
-    }
-
-
-    /** Debug thread to read debug properties - runs when debug.bt.hfp is true
-     *  at the time a bluetooth handsfree device is connected. Debug properties
-     *  are polled and mock updates sent every 1 second */
-    private class DebugThread extends Thread {
-        /** Turns on/off handsfree profile debugging mode */
-        static final String DEBUG_HANDSFREE = "debug.bt.hfp";
-
-        /** Mock battery level change - use 0 to 5 */
-        static final String DEBUG_HANDSFREE_BATTERY = "debug.bt.hfp.battery";
-
-        /** Mock no cellular service when false */
-        static final String DEBUG_HANDSFREE_SERVICE = "debug.bt.hfp.service";
-
-        /** Mock cellular roaming when true */
-        static final String DEBUG_HANDSFREE_ROAM = "debug.bt.hfp.roam";
-
-        /** false to true transition will force an audio (SCO) connection to
-         *  be established. true to false will force audio to be disconnected
-         */
-        static final String DEBUG_HANDSFREE_AUDIO = "debug.bt.hfp.audio";
-
-        /** true allows incoming SCO connection out of call.
-         */
-        static final String DEBUG_HANDSFREE_AUDIO_ANYTIME = "debug.bt.hfp.audio_anytime";
-
-        /** Mock signal strength change in ASU - use 0 to 31 */
-        static final String DEBUG_HANDSFREE_SIGNAL = "debug.bt.hfp.signal";
-
-        /** Debug AT+CLCC: print +CLCC result */
-        static final String DEBUG_HANDSFREE_CLCC = "debug.bt.hfp.clcc";
-
-        /** Debug AT+BSIR - Send In Band Ringtones Unsolicited AT command.
-         * debug.bt.unsol.inband = 0 => AT+BSIR = 0 sent by the AG
-         * debug.bt.unsol.inband = 1 => AT+BSIR = 0 sent by the AG
-         * Other values are ignored.
-         */
-
-        static final String DEBUG_UNSOL_INBAND_RINGTONE = "debug.bt.unsol.inband";
-
-        @Override
-        public void run() {
-            boolean oldService = true;
-            boolean oldRoam = false;
-            boolean oldAudio = false;
-
-            while (!isInterrupted() && inDebug()) {
-                int batteryLevel = SystemProperties.getInt(DEBUG_HANDSFREE_BATTERY, -1);
-                if (batteryLevel >= 0 && batteryLevel <= 5) {
-                    Intent intent = new Intent();
-                    intent.putExtra("level", batteryLevel);
-                    intent.putExtra("scale", 5);
-                    mBluetoothPhoneState.updateBatteryState(intent);
-                }
-
-                boolean serviceStateChanged = false;
-                if (SystemProperties.getBoolean(DEBUG_HANDSFREE_SERVICE, true) != oldService) {
-                    oldService = !oldService;
-                    serviceStateChanged = true;
-                }
-                if (SystemProperties.getBoolean(DEBUG_HANDSFREE_ROAM, false) != oldRoam) {
-                    oldRoam = !oldRoam;
-                    serviceStateChanged = true;
-                }
-                if (serviceStateChanged) {
-                    Bundle b = new Bundle();
-                    b.putInt("state", oldService ? 0 : 1);
-                    b.putBoolean("roaming", oldRoam);
-                    mBluetoothPhoneState.updateServiceState(true, ServiceState.newFromBundle(b));
-                }
-
-                if (SystemProperties.getBoolean(DEBUG_HANDSFREE_AUDIO, false) != oldAudio) {
-                    oldAudio = !oldAudio;
-                    if (oldAudio) {
-                        audioOn();
-                    } else {
-                        audioOff();
-                    }
-                }
-
-                int signalLevel = SystemProperties.getInt(DEBUG_HANDSFREE_SIGNAL, -1);
-                if (signalLevel >= 0 && signalLevel <= 31) {
-                    SignalStrength signalStrength = new SignalStrength(signalLevel, -1, -1, -1,
-                            -1, -1, -1, true);
-                    Intent intent = new Intent();
-                    Bundle data = new Bundle();
-                    signalStrength.fillInNotifierBundle(data);
-                    intent.putExtras(data);
-                    mBluetoothPhoneState.updateSignalState(intent);
-                }
-
-                if (SystemProperties.getBoolean(DEBUG_HANDSFREE_CLCC, false)) {
-                    log(gsmGetClccResult().toString());
-                }
-                try {
-                    sleep(1000);  // 1 second
-                } catch (InterruptedException e) {
-                    break;
-                }
-
-                int inBandRing =
-                    SystemProperties.getInt(DEBUG_UNSOL_INBAND_RINGTONE, -1);
-                if (inBandRing == 0 || inBandRing == 1) {
-                    AtCommandResult result =
-                        new AtCommandResult(AtCommandResult.UNSOLICITED);
-                    result.addResponse("+BSIR: " + inBandRing);
-                    sendURC(result.toString());
-                }
-            }
-        }
-    }
-
-    public void cdmaSwapSecondCallState() {
-        if (VDBG) log("cdmaSetSecondCallState: Toggling mCdmaIsSecondCallActive");
-        mCdmaIsSecondCallActive = !mCdmaIsSecondCallActive;
-        mCdmaCallsSwapped = true;
-    }
-
-    public void cdmaSetSecondCallState(boolean state) {
-        if (VDBG) log("cdmaSetSecondCallState: Setting mCdmaIsSecondCallActive to " + state);
-        mCdmaIsSecondCallActive = state;
-
-        if (!mCdmaIsSecondCallActive) {
-            mCdmaCallsSwapped = false;
-        }
-    }
-
-    private static void log(String msg) {
-        Log.d(TAG, msg);
-    }
-}
diff --git a/src/com/android/phone/BluetoothHeadsetService.java b/src/com/android/phone/BluetoothHeadsetService.java
deleted file mode 100755
index db64376..0000000
--- a/src/com/android/phone/BluetoothHeadsetService.java
+++ /dev/null
@@ -1,927 +0,0 @@
-/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.phone;
-
-import android.app.Service;
-import android.bluetooth.BluetoothAdapter;
-import android.bluetooth.BluetoothAudioGateway;
-import android.bluetooth.BluetoothAudioGateway.IncomingConnectionInfo;
-import android.bluetooth.BluetoothDevice;
-import android.bluetooth.BluetoothHeadset;
-import android.bluetooth.BluetoothProfile;
-import android.bluetooth.BluetoothUuid;
-import android.bluetooth.HeadsetBase;
-import android.bluetooth.IBluetooth;
-import android.bluetooth.IBluetoothHeadset;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.media.AudioManager;
-import android.os.Handler;
-import android.os.IBinder;
-import android.os.Message;
-import android.os.ParcelUuid;
-import android.os.PowerManager;
-import android.os.RemoteException;
-import android.os.ServiceManager;
-import android.provider.Settings;
-import android.util.Log;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.concurrent.ConcurrentHashMap;
-
-/**
- * Provides Bluetooth Headset and Handsfree profile, as a service in
- * the Phone application.
- * @hide
- */
-public class BluetoothHeadsetService extends Service {
-    private static final String TAG = "Bluetooth HSHFP";
-    private static final boolean DBG = true;
-
-    private static final String PREF_NAME = BluetoothHeadsetService.class.getSimpleName();
-    private static final String PREF_LAST_HEADSET = "lastHeadsetAddress";
-
-    private static final int PHONE_STATE_CHANGED = 1;
-
-    private static final String BLUETOOTH_ADMIN_PERM = android.Manifest.permission.BLUETOOTH_ADMIN;
-    private static final String BLUETOOTH_PERM = android.Manifest.permission.BLUETOOTH;
-
-    private static boolean sHasStarted = false;
-
-    private BluetoothDevice mDeviceSdpQuery;
-    private BluetoothAdapter mAdapter;
-    private IBluetooth mBluetoothService;
-    private PowerManager mPowerManager;
-    private BluetoothAudioGateway mAg;
-    private BluetoothHandsfree mBtHandsfree;
-    private ConcurrentHashMap<BluetoothDevice, BluetoothRemoteHeadset> mRemoteHeadsets;
-    private BluetoothDevice mAudioConnectedDevice;
-
-    @Override
-    public void onCreate() {
-        super.onCreate();
-        mAdapter = BluetoothAdapter.getDefaultAdapter();
-        mPowerManager = (PowerManager) getSystemService(Context.POWER_SERVICE);
-        mBtHandsfree = PhoneApp.getInstance().getBluetoothHandsfree();
-        mAg = new BluetoothAudioGateway(mAdapter);
-        IntentFilter filter = new IntentFilter(
-                BluetoothDevice.ACTION_ACL_DISCONNECT_REQUESTED);
-        filter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);
-        filter.addAction(AudioManager.VOLUME_CHANGED_ACTION);
-        filter.addAction(BluetoothDevice.ACTION_UUID);
-        registerReceiver(mBluetoothReceiver, filter);
-
-        IBinder b = ServiceManager.getService(BluetoothAdapter.BLUETOOTH_SERVICE);
-        if (b == null) {
-            throw new RuntimeException("Bluetooth service not available");
-        }
-        mBluetoothService = IBluetooth.Stub.asInterface(b);
-        mRemoteHeadsets = new ConcurrentHashMap<BluetoothDevice, BluetoothRemoteHeadset>();
-   }
-
-   private class BluetoothRemoteHeadset {
-       private int mState;
-       private int mAudioState;
-       private int mHeadsetType;
-       private HeadsetBase mHeadset;
-       private IncomingConnectionInfo mIncomingInfo;
-
-       BluetoothRemoteHeadset() {
-           mState = BluetoothProfile.STATE_DISCONNECTED;
-           mHeadsetType = BluetoothHandsfree.TYPE_UNKNOWN;
-           mHeadset = null;
-           mIncomingInfo = null;
-           mAudioState = BluetoothHeadset.STATE_AUDIO_DISCONNECTED;
-       }
-
-       BluetoothRemoteHeadset(int headsetType, IncomingConnectionInfo incomingInfo) {
-           mState = BluetoothProfile.STATE_DISCONNECTED;
-           mHeadsetType = headsetType;
-           mHeadset = null;
-           mIncomingInfo = incomingInfo;
-           mAudioState = BluetoothHeadset.STATE_AUDIO_DISCONNECTED;
-       }
-   }
-
-   synchronized private BluetoothDevice getCurrentDevice() {
-       for (BluetoothDevice device : mRemoteHeadsets.keySet()) {
-           int state = mRemoteHeadsets.get(device).mState;
-           if (state == BluetoothProfile.STATE_CONNECTING ||
-               state == BluetoothProfile.STATE_CONNECTED) {
-               return device;
-           }
-       }
-       return null;
-   }
-
-    @Override
-    public void onStart(Intent intent, int startId) {
-         if (mAdapter == null) {
-            Log.w(TAG, "Stopping BluetoothHeadsetService: device does not have BT");
-            stopSelf();
-        } else {
-            if (!sHasStarted) {
-                if (DBG) log("Starting BluetoothHeadsetService");
-                if (mAdapter.isEnabled()) {
-                    mAg.start(mIncomingConnectionHandler);
-                    mBtHandsfree.onBluetoothEnabled();
-                }
-                sHasStarted = true;
-            }
-        }
-    }
-
-    private final Handler mIncomingConnectionHandler = new Handler() {
-        @Override
-        public void handleMessage(Message msg) {
-            synchronized(BluetoothHeadsetService.this) {
-                IncomingConnectionInfo info = (IncomingConnectionInfo)msg.obj;
-                int type = BluetoothHandsfree.TYPE_UNKNOWN;
-                switch(msg.what) {
-                case BluetoothAudioGateway.MSG_INCOMING_HEADSET_CONNECTION:
-                    type = BluetoothHandsfree.TYPE_HEADSET;
-                    break;
-                case BluetoothAudioGateway.MSG_INCOMING_HANDSFREE_CONNECTION:
-                    type = BluetoothHandsfree.TYPE_HANDSFREE;
-                    break;
-                }
-
-                Log.i(TAG, "Incoming rfcomm (" + BluetoothHandsfree.typeToString(type) +
-                      ") connection from " + info.mRemoteDevice + "on channel " +
-                      info.mRfcommChan);
-
-                int priority = BluetoothProfile.PRIORITY_OFF;
-                HeadsetBase headset;
-                priority = getPriority(info.mRemoteDevice);
-                if (priority <= BluetoothProfile.PRIORITY_OFF) {
-                    Log.i(TAG, "Rejecting incoming connection because priority = " + priority);
-
-                    headset = new HeadsetBase(mPowerManager, mAdapter,
-                                              info.mRemoteDevice,
-                                              info.mSocketFd, info.mRfcommChan,
-                                              null);
-                    headset.disconnect();
-                    try {
-                        mBluetoothService.notifyIncomingConnection(info.mRemoteDevice.getAddress(),
-                                                                   true);
-                    } catch (RemoteException e) {
-                        Log.e(TAG, "notifyIncomingConnection", e);
-                    }
-                    return;
-                }
-
-                BluetoothRemoteHeadset remoteHeadset;
-                BluetoothDevice device = getCurrentDevice();
-
-                int state = BluetoothProfile.STATE_DISCONNECTED;
-                if (device != null) {
-                    state = mRemoteHeadsets.get(device).mState;
-                }
-
-                switch (state) {
-                case BluetoothProfile.STATE_DISCONNECTED:
-                    // headset connecting us, lets join
-                    remoteHeadset = new BluetoothRemoteHeadset(type, info);
-                    mRemoteHeadsets.put(info.mRemoteDevice, remoteHeadset);
-
-                    try {
-                        mBluetoothService.notifyIncomingConnection(
-                           info.mRemoteDevice.getAddress(), false);
-                    } catch (RemoteException e) {
-                        Log.e(TAG, "notifyIncomingConnection");
-                    }
-                    break;
-                case BluetoothProfile.STATE_CONNECTING:
-                    if (!info.mRemoteDevice.equals(device)) {
-                        // different headset, ignoring
-                        Log.i(TAG, "Already attempting connect to " + device +
-                              ", disconnecting " + info.mRemoteDevice);
-
-                        headset = new HeadsetBase(mPowerManager, mAdapter,
-                                                  info.mRemoteDevice,
-                                                  info.mSocketFd, info.mRfcommChan,
-                                                  null);
-                        headset.disconnect();
-                        break;
-                    }
-
-                    // Incoming and Outgoing connections to the same headset.
-                    // The state machine manager will cancel outgoing and accept the incoming one.
-                    // Update the state
-                    mRemoteHeadsets.get(info.mRemoteDevice).mHeadsetType = type;
-                    mRemoteHeadsets.get(info.mRemoteDevice).mIncomingInfo = info;
-
-                    try {
-                        mBluetoothService.notifyIncomingConnection(
-                            info.mRemoteDevice.getAddress(), false);
-                    } catch (RemoteException e) {
-                        Log.e(TAG, "notifyIncomingConnection");
-                    }
-                    break;
-                case BluetoothProfile.STATE_CONNECTED:
-                    Log.i(TAG, "Already connected to " + device + ", disconnecting " +
-                            info.mRemoteDevice);
-                    rejectIncomingConnection(info);
-                    break;
-                }
-            }
-        }
-    };
-
-    private void rejectIncomingConnection(IncomingConnectionInfo info) {
-        HeadsetBase headset = new HeadsetBase(mPowerManager, mAdapter,
-            info.mRemoteDevice, info.mSocketFd, info.mRfcommChan, null);
-        headset.disconnect();
-    }
-
-
-    private final BroadcastReceiver mBluetoothReceiver = new BroadcastReceiver() {
-
-        @Override
-        public void onReceive(Context context, Intent intent) {
-            String action = intent.getAction();
-            BluetoothDevice device =
-                    intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
-
-            BluetoothDevice currDevice = getCurrentDevice();
-            int state = BluetoothProfile.STATE_DISCONNECTED;
-            if (currDevice != null) {
-                state = mRemoteHeadsets.get(currDevice).mState;
-            }
-
-            if ((state == BluetoothProfile.STATE_CONNECTED ||
-                    state == BluetoothProfile.STATE_CONNECTING) &&
-                    action.equals(BluetoothDevice.ACTION_ACL_DISCONNECT_REQUESTED) &&
-                    device.equals(currDevice)) {
-                try {
-                    mBinder.disconnect(currDevice);
-                } catch (RemoteException e) {}
-            } else if (action.equals(BluetoothAdapter.ACTION_STATE_CHANGED)) {
-                switch (intent.getIntExtra(BluetoothAdapter.EXTRA_STATE,
-                                           BluetoothAdapter.ERROR)) {
-                case BluetoothAdapter.STATE_ON:
-                    mAg.start(mIncomingConnectionHandler);
-                    mBtHandsfree.onBluetoothEnabled();
-                    break;
-                case BluetoothAdapter.STATE_TURNING_OFF:
-                    mBtHandsfree.onBluetoothDisabled();
-                    mAg.stop();
-                    if (currDevice != null) {
-                        try {
-                            mBinder.disconnect(currDevice);
-                        } catch (RemoteException e) {}
-                    }
-                    break;
-                }
-            } else if (action.equals(AudioManager.VOLUME_CHANGED_ACTION)) {
-                int streamType = intent.getIntExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, -1);
-                if (streamType == AudioManager.STREAM_BLUETOOTH_SCO) {
-                    mBtHandsfree.sendScoGainUpdate(intent.getIntExtra(
-                            AudioManager.EXTRA_VOLUME_STREAM_VALUE, 0));
-                }
-
-            } else if (action.equals(BluetoothDevice.ACTION_UUID)) {
-                if (device.equals(mDeviceSdpQuery) && device.equals(currDevice)) {
-                    // We have got SDP records for the device we are interested in.
-                    getSdpRecordsAndConnect(device);
-                }
-            }
-        }
-    };
-
-    private static final int CONNECT_HEADSET_DELAYED = 1;
-    private Handler mHandler = new Handler() {
-        @Override
-        public void handleMessage(Message msg) {
-            switch (msg.what) {
-                case CONNECT_HEADSET_DELAYED:
-                    BluetoothDevice device = (BluetoothDevice) msg.obj;
-                    getSdpRecordsAndConnect(device);
-                    break;
-            }
-        }
-    };
-
-    @Override
-    public IBinder onBind(Intent intent) {
-        return mBinder;
-    }
-
-    // ------------------------------------------------------------------
-    // Bluetooth Headset Connect
-    // ------------------------------------------------------------------
-    private static final int RFCOMM_CONNECTED             = 1;
-    private static final int RFCOMM_ERROR                 = 2;
-
-    private long mTimestamp;
-
-    /**
-     * Thread for RFCOMM connection
-     * Messages are sent to mConnectingStatusHandler as connection progresses.
-     */
-    private RfcommConnectThread mConnectThread;
-    private class RfcommConnectThread extends Thread {
-        private BluetoothDevice device;
-        private int channel;
-        private int type;
-
-        private static final int EINTERRUPT = -1000;
-        private static final int ECONNREFUSED = -111;
-
-        public RfcommConnectThread(BluetoothDevice device, int channel, int type) {
-            super();
-            this.device = device;
-            this.channel = channel;
-            this.type = type;
-        }
-
-        private int waitForConnect(HeadsetBase headset) {
-            // Try to connect for 20 seconds
-            int result = 0;
-            for (int i=0; i < 40 && result == 0; i++) {
-                // waitForAsyncConnect returns 0 on timeout, 1 on success, < 0 on error.
-                result = headset.waitForAsyncConnect(500, mConnectedStatusHandler);
-                if (isInterrupted()) {
-                    headset.disconnect();
-                    return EINTERRUPT;
-                }
-            }
-            return result;
-        }
-
-        @Override
-        public void run() {
-            long timestamp;
-
-            timestamp = System.currentTimeMillis();
-            HeadsetBase headset = new HeadsetBase(mPowerManager, mAdapter,
-                                                  device, channel);
-
-            int result = waitForConnect(headset);
-
-            if (result != EINTERRUPT && result != 1) {
-                if (result == ECONNREFUSED && mDeviceSdpQuery == null) {
-                    // The rfcomm channel number might have changed, do SDP
-                    // query and try to connect again.
-                    mDeviceSdpQuery = getCurrentDevice();
-                    device.fetchUuidsWithSdp();
-                    mConnectThread = null;
-                    return;
-                } else {
-                    Log.i(TAG, "Trying to connect to rfcomm socket again after 1 sec");
-                    try {
-                      sleep(1000);  // 1 second
-                    } catch (InterruptedException e) {
-                      return;
-                    }
-                }
-                result = waitForConnect(headset);
-            }
-            mDeviceSdpQuery = null;
-            if (result == EINTERRUPT) return;
-
-            if (DBG) log("RFCOMM connection attempt took " +
-                  (System.currentTimeMillis() - timestamp) + " ms");
-            if (isInterrupted()) {
-                headset.disconnect();
-                return;
-            }
-            if (result < 0) {
-                Log.w(TAG, "headset.waitForAsyncConnect() error: " + result);
-                mConnectingStatusHandler.obtainMessage(RFCOMM_ERROR).sendToTarget();
-                return;
-            } else if (result == 0) {
-                mConnectingStatusHandler.obtainMessage(RFCOMM_ERROR).sendToTarget();
-                Log.w(TAG, "mHeadset.waitForAsyncConnect() error: " + result + "(timeout)");
-                return;
-            } else {
-                mConnectingStatusHandler.obtainMessage(RFCOMM_CONNECTED, headset).sendToTarget();
-            }
-        }
-    }
-
-    /**
-     * Receives events from mConnectThread back in the main thread.
-     */
-    private final Handler mConnectingStatusHandler = new Handler() {
-        @Override
-        public void handleMessage(Message msg) {
-            BluetoothDevice device = getCurrentDevice();
-            if (device == null ||
-                mRemoteHeadsets.get(device).mState != BluetoothProfile.STATE_CONNECTING) {
-                return;  // stale events
-            }
-
-            switch (msg.what) {
-            case RFCOMM_ERROR:
-                if (DBG) log("Rfcomm error");
-                mConnectThread = null;
-                setState(device, BluetoothProfile.STATE_DISCONNECTED);
-                break;
-            case RFCOMM_CONNECTED:
-                if (DBG) log("Rfcomm connected");
-                mConnectThread = null;
-                HeadsetBase headset = (HeadsetBase)msg.obj;
-                setState(device, BluetoothProfile.STATE_CONNECTED);
-
-                mRemoteHeadsets.get(device).mHeadset = headset;
-                mBtHandsfree.connectHeadset(headset, mRemoteHeadsets.get(device).mHeadsetType);
-                break;
-            }
-        }
-    };
-
-    /**
-     * Receives events from a connected RFCOMM socket back in the main thread.
-     */
-    private final Handler mConnectedStatusHandler = new Handler() {
-        @Override
-        public void handleMessage(Message msg) {
-            switch (msg.what) {
-            case HeadsetBase.RFCOMM_DISCONNECTED:
-                mBtHandsfree.resetAtState();
-                mBtHandsfree.setVirtualCallInProgress(false);
-                BluetoothDevice device = getCurrentDevice();
-                if (device != null) {
-                    setState(device, BluetoothProfile.STATE_DISCONNECTED);
-                }
-                break;
-            }
-        }
-    };
-
-    private synchronized void setState(BluetoothDevice device, int state) {
-        int prevState = mRemoteHeadsets.get(device).mState;
-        if (state != prevState) {
-            if (DBG) log("Device: " + device +
-                " Headset  state" + prevState + " -> " + state);
-            if (prevState == BluetoothProfile.STATE_CONNECTED) {
-                // Headset is disconnecting, stop the parser.
-                mBtHandsfree.disconnectHeadset();
-            }
-            Intent intent = new Intent(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED);
-            intent.putExtra(BluetoothProfile.EXTRA_PREVIOUS_STATE, prevState);
-            intent.putExtra(BluetoothProfile.EXTRA_STATE, state);
-            intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device);
-            if (state == BluetoothProfile.STATE_DISCONNECTED) {
-                mRemoteHeadsets.get(device).mHeadset = null;
-                mRemoteHeadsets.get(device).mHeadsetType = BluetoothHandsfree.TYPE_UNKNOWN;
-            }
-
-            mRemoteHeadsets.get(device).mState = state;
-
-            sendBroadcast(intent, BLUETOOTH_PERM);
-            if (state == BluetoothHeadset.STATE_CONNECTED) {
-                // Set the priority to AUTO_CONNECT
-                setPriority(device, BluetoothHeadset.PRIORITY_AUTO_CONNECT);
-                adjustOtherHeadsetPriorities(device);
-            }
-            try {
-                mBluetoothService.sendConnectionStateChange(device, BluetoothProfile.HEADSET,
-                                                            state, prevState);
-            } catch (RemoteException e) {
-                Log.e(TAG, "sendConnectionStateChange: exception");
-            }
-       }
-    }
-
-    private void adjustOtherHeadsetPriorities(BluetoothDevice connectedDevice) {
-       for (BluetoothDevice device : mAdapter.getBondedDevices()) {
-          if (getPriority(device) >= BluetoothHeadset.PRIORITY_AUTO_CONNECT &&
-              !device.equals(connectedDevice)) {
-              setPriority(device, BluetoothHeadset.PRIORITY_ON);
-          }
-       }
-    }
-
-    private void setPriority(BluetoothDevice device, int priority) {
-        try {
-            mBinder.setPriority(device, priority);
-        } catch (RemoteException e) {
-            Log.e(TAG, "Error while setting priority for: " + device);
-        }
-    }
-
-    private int getPriority(BluetoothDevice device) {
-        try {
-            return mBinder.getPriority(device);
-        } catch (RemoteException e) {
-            Log.e(TAG, "Error while getting priority for: " + device);
-        }
-        return BluetoothProfile.PRIORITY_UNDEFINED;
-    }
-
-    private synchronized void getSdpRecordsAndConnect(BluetoothDevice device) {
-        if (!device.equals(getCurrentDevice())) {
-            // stale
-            return;
-        }
-
-        // Check if incoming connection has already connected.
-        if (mRemoteHeadsets.get(device).mState == BluetoothProfile.STATE_CONNECTED) {
-            return;
-        }
-
-        ParcelUuid[] uuids = device.getUuids();
-        ParcelUuid[] localUuids = mAdapter.getUuids();
-        int type = BluetoothHandsfree.TYPE_UNKNOWN;
-        if (uuids != null) {
-            if (BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.Handsfree) &&
-                BluetoothUuid.isUuidPresent(localUuids, BluetoothUuid.Handsfree_AG)) {
-                log("SDP UUID: TYPE_HANDSFREE");
-                type = BluetoothHandsfree.TYPE_HANDSFREE;
-                mRemoteHeadsets.get(device).mHeadsetType = type;
-                int channel = device.getServiceChannel(BluetoothUuid.Handsfree);
-                mConnectThread = new RfcommConnectThread(device, channel, type);
-                if (mAdapter.isDiscovering()) {
-                    mAdapter.cancelDiscovery();
-                }
-                mConnectThread.start();
-                if (getPriority(device) < BluetoothHeadset.PRIORITY_AUTO_CONNECT) {
-                    setPriority(device, BluetoothHeadset.PRIORITY_AUTO_CONNECT);
-                }
-                return;
-            } else if (BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.HSP) &&
-                BluetoothUuid.isUuidPresent(localUuids, BluetoothUuid.HSP_AG)) {
-                log("SDP UUID: TYPE_HEADSET");
-                type = BluetoothHandsfree.TYPE_HEADSET;
-                mRemoteHeadsets.get(device).mHeadsetType = type;
-                int channel = device.getServiceChannel(BluetoothUuid.HSP);
-                mConnectThread = new RfcommConnectThread(device, channel, type);
-                if (mAdapter.isDiscovering()) {
-                    mAdapter.cancelDiscovery();
-                }
-                mConnectThread.start();
-                if (getPriority(device) < BluetoothHeadset.PRIORITY_AUTO_CONNECT) {
-                    setPriority(device, BluetoothHeadset.PRIORITY_AUTO_CONNECT);
-                }
-                return;
-            }
-        }
-        log("SDP UUID: TYPE_UNKNOWN");
-        mRemoteHeadsets.get(device).mHeadsetType = type;
-        setState(device, BluetoothProfile.STATE_DISCONNECTED);
-        return;
-    }
-
-    /**
-     * Handlers for incoming service calls
-     */
-    private final IBluetoothHeadset.Stub mBinder = new IBluetoothHeadset.Stub() {
-        public int getConnectionState(BluetoothDevice device) {
-            enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
-            BluetoothRemoteHeadset headset = mRemoteHeadsets.get(device);
-            if (headset == null) {
-                return BluetoothProfile.STATE_DISCONNECTED;
-            }
-            return headset.mState;
-        }
-
-        public List<BluetoothDevice> getConnectedDevices() {
-            enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
-            return getDevicesMatchingConnectionStates(
-                new int[] {BluetoothProfile.STATE_CONNECTED});
-        }
-
-        public boolean connect(BluetoothDevice device) {
-            enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
-                                           "Need BLUETOOTH_ADMIN permission");
-            synchronized (BluetoothHeadsetService.this) {
-                BluetoothDevice currDevice = getCurrentDevice();
-
-                if (currDevice == device ||
-                    getPriority(device) == BluetoothProfile.PRIORITY_OFF) {
-                    return false;
-                }
-                if (currDevice != null) {
-                    disconnect(currDevice);
-                }
-                try {
-                    return mBluetoothService.connectHeadset(device.getAddress());
-                } catch (RemoteException e) {
-                    Log.e(TAG, "connectHeadset");
-                    return false;
-                }
-            }
-        }
-
-        public boolean disconnect(BluetoothDevice device) {
-            enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
-                                           "Need BLUETOOTH_ADMIN permission");
-            synchronized (BluetoothHeadsetService.this) {
-                BluetoothRemoteHeadset headset = mRemoteHeadsets.get(device);
-                if (headset == null ||
-                    headset.mState == BluetoothProfile.STATE_DISCONNECTED ||
-                    headset.mState == BluetoothProfile.STATE_DISCONNECTING) {
-                    return false;
-                }
-                try {
-                    return mBluetoothService.disconnectHeadset(device.getAddress());
-                } catch (RemoteException e) {
-                    Log.e(TAG, "disconnectHeadset");
-                    return false;
-                }
-            }
-        }
-
-        public synchronized boolean isAudioConnected(BluetoothDevice device) {
-            enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
-            if (device.equals(mAudioConnectedDevice)) return true;
-            return false;
-        }
-
-        public synchronized List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
-            enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
-            List<BluetoothDevice> headsets = new ArrayList<BluetoothDevice>();
-            for (BluetoothDevice device: mRemoteHeadsets.keySet()) {
-                int headsetState = getConnectionState(device);
-                for (int state : states) {
-                    if (state == headsetState) {
-                        headsets.add(device);
-                        break;
-                    }
-                }
-            }
-            return headsets;
-        }
-
-        public boolean startVoiceRecognition(BluetoothDevice device) {
-            enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
-            synchronized (BluetoothHeadsetService.this) {
-                if (device == null ||
-                    mRemoteHeadsets.get(device) == null ||
-                    mRemoteHeadsets.get(device).mState != BluetoothProfile.STATE_CONNECTED) {
-                    return false;
-                }
-                return mBtHandsfree.startVoiceRecognition();
-            }
-        }
-
-        public boolean stopVoiceRecognition(BluetoothDevice device) {
-            enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
-            synchronized (BluetoothHeadsetService.this) {
-                if (device == null ||
-                    mRemoteHeadsets.get(device) == null ||
-                    mRemoteHeadsets.get(device).mState != BluetoothProfile.STATE_CONNECTED) {
-                    return false;
-                }
-
-                return mBtHandsfree.stopVoiceRecognition();
-            }
-        }
-
-        public int getBatteryUsageHint(BluetoothDevice device) {
-            enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
-
-            return HeadsetBase.getAtInputCount();
-        }
-
-        public int getPriority(BluetoothDevice device) {
-            enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
-                "Need BLUETOOTH_ADMIN permission");
-            synchronized (BluetoothHeadsetService.this) {
-                int priority = Settings.Secure.getInt(getContentResolver(),
-                        Settings.Secure.getBluetoothHeadsetPriorityKey(device.getAddress()),
-                        BluetoothProfile.PRIORITY_UNDEFINED);
-                return priority;
-            }
-        }
-
-        public boolean setPriority(BluetoothDevice device, int priority) {
-            enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
-                "Need BLUETOOTH_ADMIN permission");
-            synchronized (BluetoothHeadsetService.this) {
-                Settings.Secure.putInt(getContentResolver(),
-                        Settings.Secure.getBluetoothHeadsetPriorityKey(device.getAddress()),
-                        priority);
-                if (DBG) log("Saved priority " + device + " = " + priority);
-                return true;
-            }
-        }
-
-        public boolean createIncomingConnect(BluetoothDevice device) {
-            synchronized (BluetoothHeadsetService.this) {
-                HeadsetBase headset;
-                setState(device, BluetoothProfile.STATE_CONNECTING);
-
-                IncomingConnectionInfo info = mRemoteHeadsets.get(device).mIncomingInfo;
-                headset = new HeadsetBase(mPowerManager, mAdapter,
-                                          device,
-                                          info.mSocketFd, info.mRfcommChan,
-                                          mConnectedStatusHandler);
-
-                mRemoteHeadsets.get(device).mHeadset = headset;
-
-                mConnectingStatusHandler.obtainMessage(RFCOMM_CONNECTED, headset).sendToTarget();
-                return true;
-            }
-        }
-
-        public boolean startScoUsingVirtualVoiceCall(BluetoothDevice device) {
-            enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
-            synchronized (BluetoothHeadsetService.this) {
-                if (device == null ||
-                    mRemoteHeadsets.get(device) == null ||
-                    mRemoteHeadsets.get(device).mState != BluetoothProfile.STATE_CONNECTED ||
-                    getAudioState(device) != BluetoothHeadset.STATE_AUDIO_DISCONNECTED) {
-                    return false;
-                }
-                return mBtHandsfree.initiateScoUsingVirtualVoiceCall();
-            }
-        }
-
-        public boolean stopScoUsingVirtualVoiceCall(BluetoothDevice device) {
-            enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
-            synchronized (BluetoothHeadsetService.this) {
-                if (device == null ||
-                    mRemoteHeadsets.get(device) == null ||
-                    mRemoteHeadsets.get(device).mState != BluetoothProfile.STATE_CONNECTED ||
-                    getAudioState(device) == BluetoothHeadset.STATE_AUDIO_DISCONNECTED) {
-                    return false;
-                }
-                return mBtHandsfree.terminateScoUsingVirtualVoiceCall();
-            }
-        }
-
-        public boolean rejectIncomingConnect(BluetoothDevice device) {
-            synchronized (BluetoothHeadsetService.this) {
-                BluetoothRemoteHeadset headset = mRemoteHeadsets.get(device);
-                if (headset != null) {
-                    IncomingConnectionInfo info = headset.mIncomingInfo;
-                    rejectIncomingConnection(info);
-                } else {
-                    Log.e(TAG, "Error no record of remote headset");
-                }
-                return true;
-            }
-        }
-
-        public boolean acceptIncomingConnect(BluetoothDevice device) {
-            synchronized (BluetoothHeadsetService.this) {
-                HeadsetBase headset;
-                BluetoothRemoteHeadset cachedHeadset = mRemoteHeadsets.get(device);
-                if (cachedHeadset == null) {
-                    Log.e(TAG, "Cached Headset is Null in acceptIncomingConnect");
-                    return false;
-                }
-                IncomingConnectionInfo info = cachedHeadset.mIncomingInfo;
-                headset = new HeadsetBase(mPowerManager, mAdapter,
-                                          device,
-                                          info.mSocketFd, info.mRfcommChan,
-                                          mConnectedStatusHandler);
-
-                setState(device, BluetoothProfile.STATE_CONNECTED);
-
-                cachedHeadset.mHeadset = headset;
-                mBtHandsfree.connectHeadset(headset, cachedHeadset.mHeadsetType);
-
-                if (DBG) log("Successfully used incoming connection");
-                return true;
-            }
-        }
-
-        public  boolean cancelConnectThread() {
-            synchronized (BluetoothHeadsetService.this) {
-                if (mConnectThread != null) {
-                    // cancel the connection thread
-                    mConnectThread.interrupt();
-                    try {
-                        mConnectThread.join();
-                    } catch (InterruptedException e) {
-                        Log.e(TAG, "Connection cancelled twice?", e);
-                    }
-                    mConnectThread = null;
-                }
-                return true;
-            }
-        }
-
-        public boolean connectHeadsetInternal(BluetoothDevice device) {
-            synchronized (BluetoothHeadsetService.this) {
-                BluetoothDevice currDevice = getCurrentDevice();
-                if (currDevice == null) {
-                    BluetoothRemoteHeadset headset = new BluetoothRemoteHeadset();
-                    mRemoteHeadsets.put(device, headset);
-
-                    setState(device, BluetoothProfile.STATE_CONNECTING);
-                    if (device.getUuids() == null) {
-                        // We might not have got the UUID change notification from
-                        // Bluez yet, if we have just paired. Try after 1.5 secs.
-                        Message msg = new Message();
-                        msg.what = CONNECT_HEADSET_DELAYED;
-                        msg.obj = device;
-                        mHandler.sendMessageDelayed(msg, 1500);
-                    } else {
-                        getSdpRecordsAndConnect(device);
-                    }
-                    return true;
-                } else {
-                      Log.w(TAG, "connectHeadset(" + device + "): failed: already in state " +
-                            mRemoteHeadsets.get(currDevice).mState +
-                            " with headset " + currDevice);
-                }
-                return false;
-            }
-        }
-
-        public boolean disconnectHeadsetInternal(BluetoothDevice device) {
-            synchronized (BluetoothHeadsetService.this) {
-                BluetoothRemoteHeadset remoteHeadset = mRemoteHeadsets.get(device);
-                if (remoteHeadset == null) return false;
-
-                if (remoteHeadset.mState == BluetoothProfile.STATE_CONNECTED) {
-                    // Send a dummy battery level message to force headset
-                    // out of sniff mode so that it will immediately notice
-                    // the disconnection. We are currently sending it for
-                    // handsfree only.
-                    // TODO: Call hci_conn_enter_active_mode() from
-                    // rfcomm_send_disc() in the kernel instead.
-                    // See http://b/1716887
-                    setState(device, BluetoothProfile.STATE_DISCONNECTING);
-
-                    HeadsetBase headset = remoteHeadset.mHeadset;
-                    if (remoteHeadset.mHeadsetType == BluetoothHandsfree.TYPE_HANDSFREE) {
-                        headset.sendURC("+CIEV: 7,3");
-                    }
-
-                    if (headset != null) {
-                        headset.disconnect();
-                        headset = null;
-                    }
-                    setState(device, BluetoothProfile.STATE_DISCONNECTED);
-                    return true;
-                } else if (remoteHeadset.mState == BluetoothProfile.STATE_CONNECTING) {
-                    // The state machine would have canceled the connect thread.
-                    // Just set the state here.
-                    setState(device, BluetoothProfile.STATE_DISCONNECTED);
-                    return true;
-                }
-                return false;
-            }
-        }
-
-        public boolean setAudioState(BluetoothDevice device, int state) {
-            // mRemoteHeadsets handles put/get concurrency by itself
-            int prevState = mRemoteHeadsets.get(device).mAudioState;
-            mRemoteHeadsets.get(device).mAudioState = state;
-            if (state == BluetoothHeadset.STATE_AUDIO_CONNECTED) {
-                mAudioConnectedDevice = device;
-            } else if (state == BluetoothHeadset.STATE_AUDIO_DISCONNECTED) {
-                mAudioConnectedDevice = null;
-            }
-            Intent intent = new Intent(BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED);
-            intent.putExtra(BluetoothHeadset.EXTRA_STATE, state);
-            intent.putExtra(BluetoothHeadset.EXTRA_PREVIOUS_STATE, prevState);
-            intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device);
-            sendBroadcast(intent, android.Manifest.permission.BLUETOOTH);
-            if (DBG) log("AudioStateIntent: " + device + " State: " + state
-                         + " PrevState: " + prevState);
-            return true;
-        }
-
-        public int getAudioState(BluetoothDevice device) {
-            // mRemoteHeadsets handles put/get concurrency by itself
-            BluetoothRemoteHeadset headset = mRemoteHeadsets.get(device);
-            if (headset == null) return BluetoothHeadset.STATE_AUDIO_DISCONNECTED;
-
-            return headset.mAudioState;
-       }
-    };
-
-    @Override
-    public void onDestroy() {
-        super.onDestroy();
-        if (DBG) log("Stopping BluetoothHeadsetService");
-        unregisterReceiver(mBluetoothReceiver);
-        mBtHandsfree.onBluetoothDisabled();
-        mAg.stop();
-        sHasStarted = false;
-        BluetoothDevice device = getCurrentDevice();
-        if (device != null) {
-            setState(device, BluetoothProfile.STATE_DISCONNECTED);
-        }
-    }
-
-
-
-    private static void log(String msg) {
-        Log.d(TAG, msg);
-    }
-}
diff --git a/src/com/android/phone/BluetoothPhoneService.java b/src/com/android/phone/BluetoothPhoneService.java
new file mode 100755
index 0000000..e2f48fd
--- /dev/null
+++ b/src/com/android/phone/BluetoothPhoneService.java
@@ -0,0 +1,931 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.phone;
+
+import android.app.Service;
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothHeadset;
+import android.bluetooth.BluetoothProfile;
+import android.bluetooth.IBluetoothHeadsetPhone;
+import android.content.Context;
+import android.content.Intent;
+import android.os.AsyncResult;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Message;
+import android.os.PowerManager;
+import android.os.PowerManager.WakeLock;
+import android.os.SystemProperties;
+import android.telephony.PhoneNumberUtils;
+import android.telephony.ServiceState;
+import android.util.Log;
+
+import com.android.internal.telephony.Call;
+import com.android.internal.telephony.Connection;
+import com.android.internal.telephony.Phone;
+import com.android.internal.telephony.PhoneConstants;
+import com.android.internal.telephony.TelephonyIntents;
+import com.android.internal.telephony.CallManager;
+
+import java.io.IOException;
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * Bluetooth headset manager for the Phone app.
+ * @hide
+ */
+public class BluetoothPhoneService extends Service {
+    private static final String TAG = "BluetoothPhoneService";
+    private static final boolean DBG = (PhoneGlobals.DBG_LEVEL >= 1)
+            && (SystemProperties.getInt("ro.debuggable", 0) == 1);
+    private static final boolean VDBG = (PhoneGlobals.DBG_LEVEL >= 2);  // even more logging
+
+    private static final String MODIFY_PHONE_STATE = android.Manifest.permission.MODIFY_PHONE_STATE;
+
+    private BluetoothAdapter mAdapter;
+    private CallManager mCM;
+
+    private BluetoothHeadset mBluetoothHeadset;
+
+    private PowerManager mPowerManager;
+
+    private WakeLock mStartCallWakeLock;  // held while waiting for the intent to start call
+
+    private PhoneConstants.State mPhoneState = PhoneConstants.State.IDLE;
+    CdmaPhoneCallState.PhoneCallState mCdmaThreeWayCallState =
+                                            CdmaPhoneCallState.PhoneCallState.IDLE;
+
+    private Call.State mForegroundCallState;
+    private Call.State mRingingCallState;
+    private CallNumber mRingNumber;
+    // number of active calls
+    int mNumActive;
+    // number of background (held) calls
+    int mNumHeld;
+
+    long mBgndEarliestConnectionTime = 0;
+
+    private boolean mRoam = false;
+
+    // CDMA specific flag used in context with BT devices having display capabilities
+    // to show which Caller is active. This state might not be always true as in CDMA
+    // networks if a caller drops off no update is provided to the Phone.
+    // This flag is just used as a toggle to provide a update to the BT device to specify
+    // which caller is active.
+    private boolean mCdmaIsSecondCallActive = false;
+    private boolean mCdmaCallsSwapped = false;
+
+    private long[] mClccTimestamps; // Timestamps associated with each clcc index
+    private boolean[] mClccUsed;     // Is this clcc index in use
+
+    private static final int GSM_MAX_CONNECTIONS = 6;  // Max connections allowed by GSM
+    private static final int CDMA_MAX_CONNECTIONS = 2;  // Max connections allowed by CDMA
+
+    @Override
+    public void onCreate() {
+        super.onCreate();
+        mCM = CallManager.getInstance();
+        mAdapter = BluetoothAdapter.getDefaultAdapter();
+        if (mAdapter == null) {
+            if (VDBG) Log.d(TAG, "mAdapter null");
+            return;
+        }
+
+        mPowerManager = (PowerManager) getSystemService(Context.POWER_SERVICE);
+        mStartCallWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
+                                                       TAG + ":StartCall");
+        mStartCallWakeLock.setReferenceCounted(false);
+
+        mAdapter.getProfileProxy(this, mProfileListener, BluetoothProfile.HEADSET);
+
+        mForegroundCallState = Call.State.IDLE;
+        mRingingCallState = Call.State.IDLE;
+        mNumActive = 0;
+        mNumHeld = 0;
+        mRingNumber = new CallNumber("", 0);;
+        mRoam = false;
+
+        updateServiceState(mCM.getDefaultPhone().getServiceState());
+        handlePreciseCallStateChange(null);
+
+        if(VDBG) Log.d(TAG, "registerForServiceStateChanged");
+        // register for updates
+        // Use the service state of default phone as BT service state to
+        // avoid situation such as no cell or wifi connection but still
+        // reporting in service (since SipPhone always reports in service).
+        mCM.getDefaultPhone().registerForServiceStateChanged(mHandler,
+                                                             SERVICE_STATE_CHANGED, null);
+        mCM.registerForPreciseCallStateChanged(mHandler,
+                                               PRECISE_CALL_STATE_CHANGED, null);
+        mCM.registerForCallWaiting(mHandler,
+                                   PHONE_CDMA_CALL_WAITING, null);
+        // TODO(BT) registerForIncomingRing?
+        // TODO(BT) registerdisconnection?
+        mClccTimestamps = new long[GSM_MAX_CONNECTIONS];
+        mClccUsed = new boolean[GSM_MAX_CONNECTIONS];
+        for (int i = 0; i < GSM_MAX_CONNECTIONS; i++) {
+            mClccUsed[i] = false;
+        }
+    }
+
+    @Override
+    public void onStart(Intent intent, int startId) {
+        if (mAdapter == null) {
+            Log.w(TAG, "Stopping Bluetooth BluetoothPhoneService Service: device does not have BT");
+            stopSelf();
+        }
+        if (VDBG) Log.d(TAG, "BluetoothPhoneService started");
+    }
+
+    @Override
+    public void onDestroy() {
+        super.onDestroy();
+        if (DBG) log("Stopping Bluetooth BluetoothPhoneService Service");
+    }
+
+    @Override
+    public IBinder onBind(Intent intent) {
+        return mBinder;
+    }
+
+    private static final int SERVICE_STATE_CHANGED = 1;
+    private static final int PRECISE_CALL_STATE_CHANGED = 2;
+    private static final int PHONE_CDMA_CALL_WAITING = 3;
+    private static final int LIST_CURRENT_CALLS = 4;
+    private static final int QUERY_PHONE_STATE = 5;
+    private static final int CDMA_SWAP_SECOND_CALL_STATE = 6;
+    private static final int CDMA_SET_SECOND_CALL_STATE = 7;
+
+    private Handler mHandler = new Handler() {
+        @Override
+        public void handleMessage(Message msg) {
+            if (VDBG) Log.d(TAG, "handleMessage: " + msg.what);
+            switch(msg.what) {
+                case SERVICE_STATE_CHANGED:
+                    ServiceState state = (ServiceState) ((AsyncResult) msg.obj).result;
+                    updateServiceState(state);
+                    break;
+                case PRECISE_CALL_STATE_CHANGED:
+                case PHONE_CDMA_CALL_WAITING:
+                    Connection connection = null;
+                    if (((AsyncResult) msg.obj).result instanceof Connection) {
+                        connection = (Connection) ((AsyncResult) msg.obj).result;
+                    }
+                    handlePreciseCallStateChange(connection);
+                    break;
+                case LIST_CURRENT_CALLS:
+                    handleListCurrentCalls();
+                    break;
+                case QUERY_PHONE_STATE:
+                    handleQueryPhoneState();
+                    break;
+                case CDMA_SWAP_SECOND_CALL_STATE:
+                    handleCdmaSwapSecondCallState();
+                    break;
+                case CDMA_SET_SECOND_CALL_STATE:
+                    handleCdmaSetSecondCallState((Boolean) msg.obj);
+                    break;
+            }
+        }
+    };
+
+    private void updateBtPhoneStateAfterRadioTechnologyChange() {
+        if(VDBG) Log.d(TAG, "updateBtPhoneStateAfterRadioTechnologyChange...");
+
+        //Unregister all events from the old obsolete phone
+        mCM.getDefaultPhone().unregisterForServiceStateChanged(mHandler);
+        mCM.unregisterForPreciseCallStateChanged(mHandler);
+        mCM.unregisterForCallWaiting(mHandler);
+
+        //Register all events new to the new active phone
+        mCM.getDefaultPhone().registerForServiceStateChanged(mHandler,
+                                                             SERVICE_STATE_CHANGED, null);
+        mCM.registerForPreciseCallStateChanged(mHandler,
+                                               PRECISE_CALL_STATE_CHANGED, null);
+        mCM.registerForCallWaiting(mHandler,
+                                   PHONE_CDMA_CALL_WAITING, null);
+    }
+
+    private void updateServiceState(ServiceState state) {
+        boolean roam = state.getRoaming();
+
+        if (roam != mRoam) {
+            mRoam = roam;
+            if (mBluetoothHeadset != null) {
+                mBluetoothHeadset.roamChanged(roam);
+            }
+        }
+    }
+
+    private void handlePreciseCallStateChange(Connection connection) {
+        // get foreground call state
+        int oldNumActive = mNumActive;
+        int oldNumHeld = mNumHeld;
+        Call.State oldRingingCallState = mRingingCallState;
+        Call.State oldForegroundCallState = mForegroundCallState;
+        CallNumber oldRingNumber = mRingNumber;
+
+        Call foregroundCall = mCM.getActiveFgCall();
+
+        if (VDBG)
+            Log.d(TAG, " handlePreciseCallStateChange: foreground: " + foregroundCall +
+                " background: " + mCM.getFirstActiveBgCall() + " ringing: " +
+                mCM.getFirstActiveRingingCall());
+
+        mForegroundCallState = foregroundCall.getState();
+        /* if in transition, do not update */
+        if (mForegroundCallState == Call.State.DISCONNECTING)
+        {
+            Log.d(TAG, "handlePreciseCallStateChange. Call disconnecting, wait before update");
+            return;
+        }
+        else
+            mNumActive = (mForegroundCallState == Call.State.ACTIVE) ? 1 : 0;
+
+        Call ringingCall = mCM.getFirstActiveRingingCall();
+        mRingingCallState = ringingCall.getState();
+        mRingNumber = getCallNumber(connection, ringingCall);
+
+        if (mCM.getDefaultPhone().getPhoneType() == PhoneConstants.PHONE_TYPE_CDMA) {
+            mNumHeld = getNumHeldCdma();
+            PhoneGlobals app = PhoneGlobals.getInstance();
+            if (app.cdmaPhoneCallState != null) {
+                CdmaPhoneCallState.PhoneCallState currCdmaThreeWayCallState =
+                        app.cdmaPhoneCallState.getCurrentCallState();
+                CdmaPhoneCallState.PhoneCallState prevCdmaThreeWayCallState =
+                    app.cdmaPhoneCallState.getPreviousCallState();
+
+                log("CDMA call state: " + currCdmaThreeWayCallState + " prev state:" +
+                    prevCdmaThreeWayCallState);
+
+                if ((mBluetoothHeadset != null) &&
+                    (mCdmaThreeWayCallState != currCdmaThreeWayCallState)) {
+                    // In CDMA, the network does not provide any feedback
+                    // to the phone when the 2nd MO call goes through the
+                    // stages of DIALING > ALERTING -> ACTIVE we fake the
+                    // sequence
+                    log("CDMA 3way call state change. mNumActive: " + mNumActive +
+                        " mNumHeld: " + mNumHeld + " IsThreeWayCallOrigStateDialing: " +
+                        app.cdmaPhoneCallState.IsThreeWayCallOrigStateDialing());
+                    if ((currCdmaThreeWayCallState ==
+                            CdmaPhoneCallState.PhoneCallState.THRWAY_ACTIVE)
+                                && app.cdmaPhoneCallState.IsThreeWayCallOrigStateDialing()) {
+                        // Mimic dialing, put the call on hold, alerting
+                        mBluetoothHeadset.phoneStateChanged(0, mNumHeld,
+                            convertCallState(Call.State.IDLE, Call.State.DIALING),
+                            mRingNumber.mNumber, mRingNumber.mType);
+
+                        mBluetoothHeadset.phoneStateChanged(0, mNumHeld,
+                            convertCallState(Call.State.IDLE, Call.State.ALERTING),
+                            mRingNumber.mNumber, mRingNumber.mType);
+
+                    }
+
+                    // In CDMA, the network does not provide any feedback to
+                    // the phone when a user merges a 3way call or swaps
+                    // between two calls we need to send a CIEV response
+                    // indicating that a call state got changed which should
+                    // trigger a CLCC update request from the BT client.
+                    if (currCdmaThreeWayCallState ==
+                            CdmaPhoneCallState.PhoneCallState.CONF_CALL &&
+                            prevCdmaThreeWayCallState ==
+                              CdmaPhoneCallState.PhoneCallState.THRWAY_ACTIVE) {
+                        log("CDMA 3way conf call. mNumActive: " + mNumActive +
+                            " mNumHeld: " + mNumHeld);
+                        mBluetoothHeadset.phoneStateChanged(mNumActive, mNumHeld,
+                            convertCallState(Call.State.IDLE, mForegroundCallState),
+                            mRingNumber.mNumber, mRingNumber.mType);
+                    }
+                }
+                mCdmaThreeWayCallState = currCdmaThreeWayCallState;
+            }
+        } else {
+            mNumHeld = getNumHeldUmts();
+        }
+
+        boolean callsSwitched = false;
+        if (mCM.getDefaultPhone().getPhoneType() == PhoneConstants.PHONE_TYPE_CDMA &&
+            mCdmaThreeWayCallState == CdmaPhoneCallState.PhoneCallState.CONF_CALL) {
+            callsSwitched = mCdmaCallsSwapped;
+        } else {
+            Call backgroundCall = mCM.getFirstActiveBgCall();
+            callsSwitched =
+                (mNumHeld == 1 && ! (backgroundCall.getEarliestConnectTime() ==
+                    mBgndEarliestConnectionTime));
+            mBgndEarliestConnectionTime = backgroundCall.getEarliestConnectTime();
+        }
+
+        if (mNumActive != oldNumActive || mNumHeld != oldNumHeld ||
+            mRingingCallState != oldRingingCallState ||
+            mForegroundCallState != oldForegroundCallState ||
+            !mRingNumber.equalTo(oldRingNumber) ||
+            callsSwitched) {
+            if (mBluetoothHeadset != null) {
+                mBluetoothHeadset.phoneStateChanged(mNumActive, mNumHeld,
+                    convertCallState(mRingingCallState, mForegroundCallState),
+                    mRingNumber.mNumber, mRingNumber.mType);
+            }
+        }
+    }
+
+    private void handleListCurrentCalls() {
+        Phone phone = mCM.getDefaultPhone();
+        int phoneType = phone.getPhoneType();
+
+        // TODO(BT) handle virtual call
+
+        if (phoneType == PhoneConstants.PHONE_TYPE_CDMA) {
+            listCurrentCallsCdma();
+        } else if (phoneType == PhoneConstants.PHONE_TYPE_GSM) {
+            listCurrentCallsGsm();
+        } else {
+            Log.e(TAG, "Unexpected phone type: " + phoneType);
+        }
+        // end the result
+        // when index is 0, other parameter does not matter
+        mBluetoothHeadset.clccResponse(0, 0, 0, 0, false, "", 0);
+    }
+
+    private void handleQueryPhoneState() {
+        if (mBluetoothHeadset != null) {
+            mBluetoothHeadset.phoneStateChanged(mNumActive, mNumHeld,
+                convertCallState(mRingingCallState, mForegroundCallState),
+                mRingNumber.mNumber, mRingNumber.mType);
+        }
+    }
+
+    private int getNumHeldUmts() {
+        int countHeld = 0;
+        List<Call> heldCalls = mCM.getBackgroundCalls();
+
+        for (Call call : heldCalls) {
+            if (call.getState() == Call.State.HOLDING) {
+                countHeld++;
+            }
+        }
+        return countHeld;
+    }
+
+    private int getNumHeldCdma() {
+        int numHeld = 0;
+        PhoneGlobals app = PhoneGlobals.getInstance();
+        if (app.cdmaPhoneCallState != null) {
+            CdmaPhoneCallState.PhoneCallState curr3WayCallState =
+                app.cdmaPhoneCallState.getCurrentCallState();
+            CdmaPhoneCallState.PhoneCallState prev3WayCallState =
+                app.cdmaPhoneCallState.getPreviousCallState();
+
+            log("CDMA call state: " + curr3WayCallState + " prev state:" +
+                prev3WayCallState);
+            if (curr3WayCallState == CdmaPhoneCallState.PhoneCallState.CONF_CALL) {
+                if (prev3WayCallState == CdmaPhoneCallState.PhoneCallState.THRWAY_ACTIVE) {
+                    numHeld = 0; //0: no calls held, as now *both* the caller are active
+                } else {
+                    numHeld = 1; //1: held call and active call, as on answering a
+                    // Call Waiting, one of the caller *is* put on hold
+                }
+            } else if (curr3WayCallState == CdmaPhoneCallState.PhoneCallState.THRWAY_ACTIVE) {
+                numHeld = 1; //1: held call and active call, as on make a 3 Way Call
+                // the first caller *is* put on hold
+            } else {
+                numHeld = 0; //0: no calls held as this is a SINGLE_ACTIVE call
+            }
+        }
+        return numHeld;
+    }
+
+    private CallNumber getCallNumber(Connection connection, Call call) {
+        String number = null;
+        int type = 128;
+        // find phone number and type
+        if (connection == null) {
+            connection = call.getEarliestConnection();
+            if (connection == null) {
+                Log.e(TAG, "Could not get a handle on Connection object for the call");
+            }
+        }
+        if (connection != null) {
+            number = connection.getAddress();
+            if (number != null) {
+                type = PhoneNumberUtils.toaFromString(number);
+            }
+        }
+        if (number == null) {
+            number = "";
+        }
+        return new CallNumber(number, type);
+    }
+
+    private class CallNumber
+    {
+        private String mNumber = null;
+        private int mType = 0;
+
+        private CallNumber(String number, int type) {
+            mNumber = number;
+            mType = type;
+        }
+
+        private boolean equalTo(CallNumber callNumber) 
+        {
+            if (mType != callNumber.mType) return false;
+            
+            if (mNumber != null && mNumber.compareTo(callNumber.mNumber) == 0) {
+                return true;
+            }
+            return false;
+        }
+    }
+
+    private BluetoothProfile.ServiceListener mProfileListener =
+            new BluetoothProfile.ServiceListener() {
+        public void onServiceConnected(int profile, BluetoothProfile proxy) {
+            mBluetoothHeadset = (BluetoothHeadset) proxy;
+        }
+        public void onServiceDisconnected(int profile) {
+            mBluetoothHeadset = null;
+        }
+    };
+
+    private void listCurrentCallsGsm() {
+        // Collect all known connections
+        // clccConnections isindexed by CLCC index
+        Connection[] clccConnections = new Connection[GSM_MAX_CONNECTIONS];
+        LinkedList<Connection> newConnections = new LinkedList<Connection>();
+        LinkedList<Connection> connections = new LinkedList<Connection>();
+
+        Call foregroundCall = mCM.getActiveFgCall();
+        Call backgroundCall = mCM.getFirstActiveBgCall();
+        Call ringingCall = mCM.getFirstActiveRingingCall();
+
+        if (ringingCall.getState().isAlive()) {
+            connections.addAll(ringingCall.getConnections());
+        }
+        if (foregroundCall.getState().isAlive()) {
+            connections.addAll(foregroundCall.getConnections());
+        }
+        if (backgroundCall.getState().isAlive()) {
+            connections.addAll(backgroundCall.getConnections());
+        }
+
+        // Mark connections that we already known about
+        boolean clccUsed[] = new boolean[GSM_MAX_CONNECTIONS];
+        for (int i = 0; i < GSM_MAX_CONNECTIONS; i++) {
+            clccUsed[i] = mClccUsed[i];
+            mClccUsed[i] = false;
+        }
+        for (Connection c : connections) {
+            boolean found = false;
+            long timestamp = c.getCreateTime();
+            for (int i = 0; i < GSM_MAX_CONNECTIONS; i++) {
+                if (clccUsed[i] && timestamp == mClccTimestamps[i]) {
+                    mClccUsed[i] = true;
+                    found = true;
+                    clccConnections[i] = c;
+                    break;
+                }
+            }
+            if (!found) {
+                newConnections.add(c);
+            }
+        }
+
+        // Find a CLCC index for new connections
+        while (!newConnections.isEmpty()) {
+            // Find lowest empty index
+            int i = 0;
+            while (mClccUsed[i]) i++;
+            // Find earliest connection
+            long earliestTimestamp = newConnections.get(0).getCreateTime();
+            Connection earliestConnection = newConnections.get(0);
+            for (int j = 0; j < newConnections.size(); j++) {
+                long timestamp = newConnections.get(j).getCreateTime();
+                if (timestamp < earliestTimestamp) {
+                    earliestTimestamp = timestamp;
+                    earliestConnection = newConnections.get(j);
+                }
+            }
+
+            // update
+            mClccUsed[i] = true;
+            mClccTimestamps[i] = earliestTimestamp;
+            clccConnections[i] = earliestConnection;
+            newConnections.remove(earliestConnection);
+        }
+
+        // Send CLCC response to Bluetooth headset service
+        for (int i = 0; i < clccConnections.length; i++) {
+            if (mClccUsed[i]) {
+                sendClccResponseGsm(i, clccConnections[i]);
+            }
+        }
+    }
+
+    /** Convert a Connection object into a single +CLCC result */
+    private void sendClccResponseGsm(int index, Connection connection) {
+        int state = convertCallState(connection.getState());
+        boolean mpty = false;
+        Call call = connection.getCall();
+        if (call != null) {
+            mpty = call.isMultiparty();
+        }
+
+        int direction = connection.isIncoming() ? 1 : 0;
+
+        String number = connection.getAddress();
+        int type = -1;
+        if (number != null) {
+            type = PhoneNumberUtils.toaFromString(number);
+        }
+
+        mBluetoothHeadset.clccResponse(index + 1, direction, state, 0, mpty, number, type);
+    }
+
+    /** Build the +CLCC result for CDMA
+     *  The complexity arises from the fact that we need to maintain the same
+     *  CLCC index even as a call moves between states. */
+    private synchronized void listCurrentCallsCdma() {
+        // In CDMA at one time a user can have only two live/active connections
+        Connection[] clccConnections = new Connection[CDMA_MAX_CONNECTIONS];// indexed by CLCC index
+        Call foregroundCall = mCM.getActiveFgCall();
+        Call ringingCall = mCM.getFirstActiveRingingCall();
+
+        Call.State ringingCallState = ringingCall.getState();
+        // If the Ringing Call state is INCOMING, that means this is the very first call
+        // hence there should not be any Foreground Call
+        if (ringingCallState == Call.State.INCOMING) {
+            if (VDBG) log("Filling clccConnections[0] for INCOMING state");
+            clccConnections[0] = ringingCall.getLatestConnection();
+        } else if (foregroundCall.getState().isAlive()) {
+            // Getting Foreground Call connection based on Call state
+            if (ringingCall.isRinging()) {
+                if (VDBG) log("Filling clccConnections[0] & [1] for CALL WAITING state");
+                clccConnections[0] = foregroundCall.getEarliestConnection();
+                clccConnections[1] = ringingCall.getLatestConnection();
+            } else {
+                if (foregroundCall.getConnections().size() <= 1) {
+                    // Single call scenario
+                    if (VDBG) {
+                        log("Filling clccConnections[0] with ForgroundCall latest connection");
+                    }
+                    clccConnections[0] = foregroundCall.getLatestConnection();
+                } else {
+                    // Multiple Call scenario. This would be true for both
+                    // CONF_CALL and THRWAY_ACTIVE state
+                    if (VDBG) {
+                        log("Filling clccConnections[0] & [1] with ForgroundCall connections");
+                    }
+                    clccConnections[0] = foregroundCall.getEarliestConnection();
+                    clccConnections[1] = foregroundCall.getLatestConnection();
+                }
+            }
+        }
+
+        // Update the mCdmaIsSecondCallActive flag based on the Phone call state
+        if (PhoneGlobals.getInstance().cdmaPhoneCallState.getCurrentCallState()
+                == CdmaPhoneCallState.PhoneCallState.SINGLE_ACTIVE) {
+            Message msg = mHandler.obtainMessage(CDMA_SET_SECOND_CALL_STATE, false);
+            mHandler.sendMessage(msg);
+        } else if (PhoneGlobals.getInstance().cdmaPhoneCallState.getCurrentCallState()
+                == CdmaPhoneCallState.PhoneCallState.THRWAY_ACTIVE) {
+            Message msg = mHandler.obtainMessage(CDMA_SET_SECOND_CALL_STATE, true);
+            mHandler.sendMessage(msg);
+        }
+
+        // send CLCC result
+        for (int i = 0; (i < clccConnections.length) && (clccConnections[i] != null); i++) {
+            sendClccResponseCdma(i, clccConnections[i]);
+        }
+    }
+
+    /** Send ClCC results for a Connection object for CDMA phone */
+    private void sendClccResponseCdma(int index, Connection connection) {
+        int state;
+        PhoneGlobals app = PhoneGlobals.getInstance();
+        CdmaPhoneCallState.PhoneCallState currCdmaCallState =
+                app.cdmaPhoneCallState.getCurrentCallState();
+        CdmaPhoneCallState.PhoneCallState prevCdmaCallState =
+                app.cdmaPhoneCallState.getPreviousCallState();
+
+        if ((prevCdmaCallState == CdmaPhoneCallState.PhoneCallState.THRWAY_ACTIVE)
+                && (currCdmaCallState == CdmaPhoneCallState.PhoneCallState.CONF_CALL)) {
+            // If the current state is reached after merging two calls
+            // we set the state of all the connections as ACTIVE
+            state = CALL_STATE_ACTIVE;
+        } else {
+            Call.State callState = connection.getState();
+            switch (callState) {
+            case ACTIVE:
+                // For CDMA since both the connections are set as active by FW after accepting
+                // a Call waiting or making a 3 way call, we need to set the state specifically
+                // to ACTIVE/HOLDING based on the mCdmaIsSecondCallActive flag. This way the
+                // CLCC result will allow BT devices to enable the swap or merge options
+                if (index == 0) { // For the 1st active connection
+                    state = mCdmaIsSecondCallActive ? CALL_STATE_HELD : CALL_STATE_ACTIVE;
+                } else { // for the 2nd active connection
+                    state = mCdmaIsSecondCallActive ? CALL_STATE_ACTIVE : CALL_STATE_HELD;
+                }
+                break;
+            case HOLDING:
+                state = CALL_STATE_HELD;
+                break;
+            case DIALING:
+                state = CALL_STATE_DIALING;
+                break;
+            case ALERTING:
+                state = CALL_STATE_ALERTING;
+                break;
+            case INCOMING:
+                state = CALL_STATE_INCOMING;
+                break;
+            case WAITING:
+                state = CALL_STATE_WAITING;
+                break;
+            default:
+                Log.e(TAG, "bad call state: " + callState);
+                return;
+            }
+        }
+
+        boolean mpty = false;
+        if (currCdmaCallState == CdmaPhoneCallState.PhoneCallState.CONF_CALL) {
+            if (prevCdmaCallState == CdmaPhoneCallState.PhoneCallState.THRWAY_ACTIVE) {
+                // If the current state is reached after merging two calls
+                // we set the multiparty call true.
+                mpty = true;
+            } // else
+                // CALL_CONF state is not from merging two calls, but from
+                // accepting the second call. In this case first will be on
+                // hold in most cases but in some cases its already merged.
+                // However, we will follow the common case and the test case
+                // as per Bluetooth SIG PTS
+        }
+
+        int direction = connection.isIncoming() ? 1 : 0;
+
+        String number = connection.getAddress();
+        int type = -1;
+        if (number != null) {
+            type = PhoneNumberUtils.toaFromString(number);
+        } else {
+            number = "";
+        }
+
+        mBluetoothHeadset.clccResponse(index + 1, direction, state, 0, mpty, number, type);
+    }
+
+    private void handleCdmaSwapSecondCallState() {
+        if (VDBG) log("cdmaSwapSecondCallState: Toggling mCdmaIsSecondCallActive");
+        mCdmaIsSecondCallActive = !mCdmaIsSecondCallActive;
+        mCdmaCallsSwapped = true;
+    }
+
+    private void handleCdmaSetSecondCallState(boolean state) {
+        if (VDBG) log("cdmaSetSecondCallState: Setting mCdmaIsSecondCallActive to " + state);
+        mCdmaIsSecondCallActive = state;
+
+        if (!mCdmaIsSecondCallActive) {
+            mCdmaCallsSwapped = false;
+        }
+    }
+
+    private final IBluetoothHeadsetPhone.Stub mBinder = new IBluetoothHeadsetPhone.Stub() {
+        public boolean answerCall() {
+            enforceCallingOrSelfPermission(MODIFY_PHONE_STATE, null);
+            return PhoneUtils.answerCall(mCM.getFirstActiveRingingCall());
+        }
+
+        public boolean hangupCall() {
+            enforceCallingOrSelfPermission(MODIFY_PHONE_STATE, null);
+            if (mCM.hasActiveFgCall()) {
+                return PhoneUtils.hangupActiveCall(mCM.getActiveFgCall());
+            } else if (mCM.hasActiveRingingCall()) {
+                return PhoneUtils.hangupRingingCall(mCM.getFirstActiveRingingCall());
+            } else if (mCM.hasActiveBgCall()) {
+                return PhoneUtils.hangupHoldingCall(mCM.getFirstActiveBgCall());
+            }
+            // TODO(BT) handle virtual voice call
+            return false;
+        }
+
+        public boolean sendDtmf(int dtmf) {
+            enforceCallingOrSelfPermission(MODIFY_PHONE_STATE, null);
+            return mCM.sendDtmf((char) dtmf);
+        }
+
+        public boolean processChld(int chld) {
+            enforceCallingOrSelfPermission(MODIFY_PHONE_STATE, null);
+            Phone phone = mCM.getDefaultPhone();
+            int phoneType = phone.getPhoneType();
+            Call ringingCall = mCM.getFirstActiveRingingCall();
+            Call backgroundCall = mCM.getFirstActiveBgCall();
+
+            if (chld == CHLD_TYPE_RELEASEHELD) {
+                if (ringingCall.isRinging()) {
+                    return PhoneUtils.hangupRingingCall(ringingCall);
+                } else {
+                    return PhoneUtils.hangupHoldingCall(backgroundCall);
+                }
+            } else if (chld == CHLD_TYPE_RELEASEACTIVE_ACCEPTHELD) {
+                if (phoneType == PhoneConstants.PHONE_TYPE_CDMA) {
+                    if (ringingCall.isRinging()) {
+                        // Hangup the active call and then answer call waiting call.
+                        if (VDBG) log("CHLD:1 Callwaiting Answer call");
+                        PhoneUtils.hangupRingingAndActive(phone);
+                    } else {
+                        // If there is no Call waiting then just hangup
+                        // the active call. In CDMA this mean that the complete
+                        // call session would be ended
+                        if (VDBG) log("CHLD:1 Hangup Call");
+                        PhoneUtils.hangup(PhoneGlobals.getInstance().mCM);
+                    }
+                    return true;
+                } else if (phoneType == PhoneConstants.PHONE_TYPE_GSM) {
+                    // Hangup active call, answer held call
+                    return PhoneUtils.answerAndEndActive(PhoneGlobals.getInstance().mCM, ringingCall);
+                } else {
+                    Log.e(TAG, "bad phone type: " + phoneType);
+                    return false;
+                }
+            } else if (chld == CHLD_TYPE_HOLDACTIVE_ACCEPTHELD) {
+                if (phoneType == PhoneConstants.PHONE_TYPE_CDMA) {
+                    // For CDMA, the way we switch to a new incoming call is by
+                    // calling PhoneUtils.answerCall(). switchAndHoldActive() won't
+                    // properly update the call state within telephony.
+                    // If the Phone state is already in CONF_CALL then we simply send
+                    // a flash cmd by calling switchHoldingAndActive()
+                    if (ringingCall.isRinging()) {
+                        if (VDBG) log("CHLD:2 Callwaiting Answer call");
+                        PhoneUtils.answerCall(ringingCall);
+                        PhoneUtils.setMute(false);
+                        // Setting the second callers state flag to TRUE (i.e. active)
+                        cdmaSetSecondCallState(true);
+                        return true;
+                    } else if (PhoneGlobals.getInstance().cdmaPhoneCallState
+                               .getCurrentCallState()
+                               == CdmaPhoneCallState.PhoneCallState.CONF_CALL) {
+                        if (VDBG) log("CHLD:2 Swap Calls");
+                        PhoneUtils.switchHoldingAndActive(backgroundCall);
+                        // Toggle the second callers active state flag
+                        cdmaSwapSecondCallState();
+                        return true;
+                    }
+                    Log.e(TAG, "CDMA fail to do hold active and accept held");
+                    return false;
+                } else if (phoneType == PhoneConstants.PHONE_TYPE_GSM) {
+                    PhoneUtils.switchHoldingAndActive(backgroundCall);
+                    return true;
+                } else {
+                    Log.e(TAG, "Unexpected phone type: " + phoneType);
+                    return false;
+                }
+            } else if (chld == CHLD_TYPE_ADDHELDTOCONF) {
+                if (phoneType == PhoneConstants.PHONE_TYPE_CDMA) {
+                    CdmaPhoneCallState.PhoneCallState state =
+                        PhoneGlobals.getInstance().cdmaPhoneCallState.getCurrentCallState();
+                    // For CDMA, we need to check if the call is in THRWAY_ACTIVE state
+                    if (state == CdmaPhoneCallState.PhoneCallState.THRWAY_ACTIVE) {
+                        if (VDBG) log("CHLD:3 Merge Calls");
+                        PhoneUtils.mergeCalls();
+                        return true;
+                    }   else if (state == CdmaPhoneCallState.PhoneCallState.CONF_CALL) {
+                        // State is CONF_CALL already and we are getting a merge call
+                        // This can happen when CONF_CALL was entered from a Call Waiting
+                        // TODO(BT)
+                        return false;
+                    }
+                    Log.e(TAG, "GSG no call to add conference");
+                    return false;
+                } else if (phoneType == PhoneConstants.PHONE_TYPE_GSM) {
+                    if (mCM.hasActiveFgCall() && mCM.hasActiveBgCall()) {
+                        PhoneUtils.mergeCalls();
+                        return true;
+                    } else {
+                        Log.e(TAG, "GSG no call to merge");
+                        return false;
+                    }
+                } else {
+                    Log.e(TAG, "Unexpected phone type: " + phoneType);
+                    return false;
+                }                
+            } else {
+                Log.e(TAG, "bad CHLD value: " + chld);
+                return false;
+            }
+        }
+
+        public String getNetworkOperator() {
+            enforceCallingOrSelfPermission(MODIFY_PHONE_STATE, null);
+            return mCM.getDefaultPhone().getServiceState().getOperatorAlphaLong();
+        }
+
+        public String getSubscriberNumber() {
+            enforceCallingOrSelfPermission(MODIFY_PHONE_STATE, null);
+            return mCM.getDefaultPhone().getLine1Number();
+        }
+
+        public boolean listCurrentCalls() {
+            enforceCallingOrSelfPermission(MODIFY_PHONE_STATE, null);
+            Message msg = Message.obtain(mHandler, LIST_CURRENT_CALLS);
+            mHandler.sendMessage(msg);
+            return true;
+        }
+
+        public boolean queryPhoneState() {
+            enforceCallingOrSelfPermission(MODIFY_PHONE_STATE, null);
+            Message msg = Message.obtain(mHandler, QUERY_PHONE_STATE);
+            mHandler.sendMessage(msg);
+            return true;
+        }
+
+        public void updateBtHandsfreeAfterRadioTechnologyChange() {
+            enforceCallingOrSelfPermission(MODIFY_PHONE_STATE, null);
+            if (VDBG) Log.d(TAG, "updateBtHandsfreeAfterRadioTechnologyChange...");
+            updateBtPhoneStateAfterRadioTechnologyChange();
+        }
+
+        public void cdmaSwapSecondCallState() {
+            enforceCallingOrSelfPermission(MODIFY_PHONE_STATE, null);
+            Message msg = Message.obtain(mHandler, CDMA_SWAP_SECOND_CALL_STATE);
+            mHandler.sendMessage(msg);
+        }
+
+        public void cdmaSetSecondCallState(boolean state) {
+            enforceCallingOrSelfPermission(MODIFY_PHONE_STATE, null);
+            Message msg = mHandler.obtainMessage(CDMA_SET_SECOND_CALL_STATE, state);
+            mHandler.sendMessage(msg);
+        }
+    };
+
+    // match up with bthf_call_state_t of bt_hf.h
+    final static int CALL_STATE_ACTIVE = 0;
+    final static int CALL_STATE_HELD = 1;
+    final static int CALL_STATE_DIALING = 2;
+    final static int CALL_STATE_ALERTING = 3;
+    final static int CALL_STATE_INCOMING = 4;
+    final static int CALL_STATE_WAITING = 5;
+    final static int CALL_STATE_IDLE = 6;
+
+    // match up with bthf_chld_type_t of bt_hf.h
+    final static int CHLD_TYPE_RELEASEHELD = 0;
+    final static int CHLD_TYPE_RELEASEACTIVE_ACCEPTHELD = 1;
+    final static int CHLD_TYPE_HOLDACTIVE_ACCEPTHELD = 2;
+    final static int CHLD_TYPE_ADDHELDTOCONF = 3;
+
+     /* Convert telephony phone call state into hf hal call state */
+    static int convertCallState(Call.State ringingState, Call.State foregroundState) {
+        if ((ringingState == Call.State.INCOMING) ||
+            (ringingState == Call.State.WAITING) )
+            return CALL_STATE_INCOMING;
+        else if (foregroundState == Call.State.DIALING)
+            return CALL_STATE_DIALING;
+        else if (foregroundState == Call.State.ALERTING)
+            return CALL_STATE_ALERTING;
+        else
+            return CALL_STATE_IDLE;
+    }
+
+    static int convertCallState(Call.State callState) {
+        switch (callState) {
+        case IDLE:
+        case DISCONNECTED:
+        case DISCONNECTING:
+            return CALL_STATE_IDLE;
+        case ACTIVE:
+            return CALL_STATE_ACTIVE;
+        case HOLDING:
+            return CALL_STATE_HELD;
+        case DIALING:
+            return CALL_STATE_DIALING;
+        case ALERTING:
+            return CALL_STATE_ALERTING;
+        case INCOMING:
+            return CALL_STATE_INCOMING;
+        case WAITING:
+            return CALL_STATE_WAITING;
+        default:
+            Log.e(TAG, "bad call state: " + callState);
+            return CALL_STATE_IDLE;
+        }
+    }
+
+    private static void log(String msg) {
+        Log.d(TAG, msg);
+    }
+}
diff --git a/src/com/android/phone/CLIRListPreference.java b/src/com/android/phone/CLIRListPreference.java
index b23277a..198bdb0 100644
--- a/src/com/android/phone/CLIRListPreference.java
+++ b/src/com/android/phone/CLIRListPreference.java
@@ -20,7 +20,7 @@
  */
 public class CLIRListPreference extends ListPreference {
     private static final String LOG_TAG = "CLIRListPreference";
-    private final boolean DBG = (PhoneApp.DBG_LEVEL >= 2);
+    private final boolean DBG = (PhoneGlobals.DBG_LEVEL >= 2);
 
     private final MyHandler mHandler = new MyHandler();
     private final Phone mPhone;
@@ -31,7 +31,7 @@
     public CLIRListPreference(Context context, AttributeSet attrs) {
         super(context, attrs);
 
-        mPhone = PhoneApp.getPhone();
+        mPhone = PhoneGlobals.getPhone();
     }
 
     public CLIRListPreference(Context context) {
diff --git a/src/com/android/phone/CallCard.java b/src/com/android/phone/CallCard.java
index 77702d1..4c6822c 100644
--- a/src/com/android/phone/CallCard.java
+++ b/src/com/android/phone/CallCard.java
@@ -33,6 +33,7 @@
 import android.text.format.DateUtils;
 import android.util.AttributeSet;
 import android.util.Log;
+import android.view.Gravity;
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.ViewStub;
@@ -61,7 +62,7 @@
         implements CallTime.OnTickListener, CallerInfoAsyncQuery.OnQueryCompleteListener,
                    ContactsAsyncHelper.OnImageLoadCompleteListener {
     private static final String LOG_TAG = "CallCard";
-    private static final boolean DBG = (PhoneApp.DBG_LEVEL >= 2);
+    private static final boolean DBG = (PhoneGlobals.DBG_LEVEL >= 2);
 
     private static final int TOKEN_UPDATE_PHOTO_FOR_CALL_STATE = 0;
     private static final int TOKEN_DO_NOTHING = 1;
@@ -89,7 +90,7 @@
     private InCallScreen mInCallScreen;
 
     // Phone app instance
-    private PhoneApp mApplication;
+    private PhoneGlobals mApplication;
 
     // Top-level subviews of the CallCard
     /** Container for info about the current call(s) */
@@ -181,7 +182,7 @@
         if (DBG) log("- this = " + this);
         if (DBG) log("- context " + context + ", attrs " + attrs);
 
-        mApplication = PhoneApp.getInstance();
+        mApplication = PhoneGlobals.getInstance();
 
         mCallTime = new CallTime(this);
 
@@ -255,8 +256,12 @@
         Call fgCall = cm.getActiveFgCall();
         Call bgCall = cm.getFirstActiveBgCall();
 
-        // Update the overall layout of the onscreen elements.
-        updateCallInfoLayout(state);
+        // Update the overall layout of the onscreen elements, if in PORTRAIT.
+        // Portrait uses a programatically altered layout, whereas landscape uses layout xml's.
+        // Landscape view has the views side by side, so no shifting of the picture is needed
+        if (!PhoneUtils.isLandscape(this.getContext())) {
+            updateCallInfoLayout(state);
+        }
 
         // If the FG call is dialing/alerting, we should display for that call
         // and ignore the ringing call. This case happens when the telephony
@@ -810,7 +815,7 @@
                 // Display "Dialing" while dialing a 3Way call, even
                 // though the foreground call state is actually ACTIVE.
                 callStateLabel = context.getString(R.string.card_title_dialing);
-            } else if (PhoneApp.getInstance().notifier.getIsCdmaRedialCall()) {
+            } else if (PhoneGlobals.getInstance().notifier.getIsCdmaRedialCall()) {
                 callStateLabel = context.getString(R.string.card_title_redialing);
             }
         }
@@ -866,6 +871,14 @@
             }
         } else {
             mCallStateLabel.setVisibility(View.GONE);
+            // Gravity is aligned left when receiving an incoming call in landscape.
+            // In that rare case, the gravity needs to be reset to the right.
+            // Also, setText("") is used since there is a delay in making the view GONE,
+            // so the user will otherwise see the text jump to the right side before disappearing.
+            if(mCallStateLabel.getGravity() != Gravity.RIGHT) {
+                mCallStateLabel.setText("");
+                mCallStateLabel.setGravity(Gravity.RIGHT);
+            }
         }
         if (skipAnimation) {
             // Restore LayoutTransition object to recover animation.
@@ -942,7 +955,7 @@
     private void displaySecondaryCallStatus(CallManager cm, Call call) {
         if (DBG) log("displayOnHoldCallStatus(call =" + call + ")...");
 
-        if ((call == null) || (PhoneApp.getInstance().isOtaCallInActiveState())) {
+        if ((call == null) || (PhoneGlobals.getInstance().isOtaCallInActiveState())) {
             mSecondaryCallInfo.setVisibility(View.GONE);
             return;
         }
@@ -999,7 +1012,7 @@
                     List<Connection> connections = call.getConnections();
                     if (connections.size() > 2) {
                         // This means that current Mobile Originated call is the not the first 3-Way
-                        // call the user is making, which in turn tells the PhoneApp that we no
+                        // call the user is making, which in turn tells the PhoneGlobals that we no
                         // longer know which previous caller/party had dropped out before the user
                         // made this call.
                         mSecondaryCallName.setText(
diff --git a/src/com/android/phone/CallController.java b/src/com/android/phone/CallController.java
index d9ec62d..e33e442 100644
--- a/src/com/android/phone/CallController.java
+++ b/src/com/android/phone/CallController.java
@@ -61,14 +61,14 @@
 public class CallController extends Handler {
     private static final String TAG = "CallController";
     private static final boolean DBG =
-            (PhoneApp.DBG_LEVEL >= 1) && (SystemProperties.getInt("ro.debuggable", 0) == 1);
+            (PhoneGlobals.DBG_LEVEL >= 1) && (SystemProperties.getInt("ro.debuggable", 0) == 1);
     // Do not check in with VDBG = true, since that may write PII to the system log.
     private static final boolean VDBG = false;
 
     /** The singleton CallController instance. */
     private static CallController sInstance;
 
-    private PhoneApp mApp;
+    private PhoneGlobals mApp;
     private CallManager mCM;
 
     /** Helper object for emergency calls in some rare use cases.  Created lazily. */
@@ -100,7 +100,7 @@
      * PhoneApp's public "callController" field, which is why there's no
      * getInstance() method here.
      */
-    /* package */ static CallController init(PhoneApp app) {
+    /* package */ static CallController init(PhoneGlobals app) {
         synchronized (CallController.class) {
             if (sInstance == null) {
                 sInstance = new CallController(app);
@@ -115,7 +115,7 @@
      * Private constructor (this is a singleton).
      * @see init()
      */
-    private CallController(PhoneApp app) {
+    private CallController(PhoneGlobals app) {
         if (DBG) log("CallController constructor: app = " + app);
         mApp = app;
         mCM = app.mCM;
diff --git a/src/com/android/phone/CallFeaturesSetting.java b/src/com/android/phone/CallFeaturesSetting.java
index 53ee8f4..ee1233d 100644
--- a/src/com/android/phone/CallFeaturesSetting.java
+++ b/src/com/android/phone/CallFeaturesSetting.java
@@ -39,6 +39,7 @@
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.Message;
+import android.os.UserHandle;
 import android.os.Vibrator;
 import android.preference.CheckBoxPreference;
 import android.preference.ListPreference;
@@ -95,7 +96,7 @@
         EditPhoneNumberPreference.OnDialogClosedListener,
         EditPhoneNumberPreference.GetDefaultNumberListener{
     private static final String LOG_TAG = "CallFeaturesSetting";
-    private static final boolean DBG = (PhoneApp.DBG_LEVEL >= 2);
+    private static final boolean DBG = (PhoneGlobals.DBG_LEVEL >= 2);
 
     /**
      * Intent action to bring up Voicemail Provider settings.
@@ -474,8 +475,8 @@
         } else if (preference == mButtonTTY) {
             return true;
         } else if (preference == mButtonAutoRetry) {
-            android.provider.Settings.System.putInt(mPhone.getContext().getContentResolver(),
-                    android.provider.Settings.System.CALL_AUTO_RETRY,
+            android.provider.Settings.Global.putInt(mPhone.getContext().getContentResolver(),
+                    android.provider.Settings.Global.CALL_AUTO_RETRY,
                     mButtonAutoRetry.isChecked() ? 1 : 0);
             return true;
         } else if (preference == mButtonHAC) {
@@ -1482,7 +1483,7 @@
     protected void onCreate(Bundle icicle) {
         super.onCreate(icicle);
         if (DBG) log("onCreate(). Intent: " + getIntent());
-        mPhone = PhoneApp.getPhone();
+        mPhone = PhoneGlobals.getPhone();
 
         addPreferencesFromResource(R.xml.call_feature_setting);
 
@@ -1725,8 +1726,8 @@
         }
 
         if (mButtonAutoRetry != null) {
-            int autoretry = Settings.System.getInt(getContentResolver(),
-                    Settings.System.CALL_AUTO_RETRY, 0);
+            int autoretry = Settings.Global.getInt(getContentResolver(),
+                    Settings.Global.CALL_AUTO_RETRY, 0);
             mButtonAutoRetry.setChecked(autoretry != 0);
         }
 
@@ -1799,7 +1800,7 @@
             updatePreferredTtyModeSummary(buttonTtyMode);
             Intent ttyModeChanged = new Intent(TtyIntent.TTY_PREFERRED_MODE_CHANGE_ACTION);
             ttyModeChanged.putExtra(TtyIntent.TTY_PREFFERED_MODE, buttonTtyMode);
-            sendBroadcast(ttyModeChanged);
+            sendBroadcastAsUser(ttyModeChanged, UserHandle.ALL);
         }
     }
 
diff --git a/src/com/android/phone/CallForwardEditPreference.java b/src/com/android/phone/CallForwardEditPreference.java
index 544d4c2..f925022 100644
--- a/src/com/android/phone/CallForwardEditPreference.java
+++ b/src/com/android/phone/CallForwardEditPreference.java
@@ -21,7 +21,7 @@
 
 public class CallForwardEditPreference extends EditPhoneNumberPreference {
     private static final String LOG_TAG = "CallForwardEditPreference";
-    private static final boolean DBG = (PhoneApp.DBG_LEVEL >= 2);
+    private static final boolean DBG = (PhoneGlobals.DBG_LEVEL >= 2);
 
     private static final String SRC_TAGS[]       = {"{0}"};
     private CharSequence mSummaryOnTemplate;
@@ -43,7 +43,7 @@
     public CallForwardEditPreference(Context context, AttributeSet attrs) {
         super(context, attrs);
 
-        phone = PhoneApp.getPhone();
+        phone = PhoneGlobals.getPhone();
         mSummaryOnTemplate = this.getSummaryOn();
 
         TypedArray a = context.obtainStyledAttributes(attrs,
diff --git a/src/com/android/phone/CallNotifier.java b/src/com/android/phone/CallNotifier.java
index dee75de..99636df 100755
--- a/src/com/android/phone/CallNotifier.java
+++ b/src/com/android/phone/CallNotifier.java
@@ -31,6 +31,9 @@
 import com.android.internal.telephony.cdma.SignalToneUtil;
 
 import android.app.ActivityManagerNative;
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothHeadset;
+import android.bluetooth.BluetoothProfile;
 import android.content.Context;
 import android.media.AudioManager;
 import android.media.ToneGenerator;
@@ -61,8 +64,8 @@
         implements CallerInfoAsyncQuery.OnQueryCompleteListener {
     private static final String LOG_TAG = "CallNotifier";
     private static final boolean DBG =
-            (PhoneApp.DBG_LEVEL >= 1) && (SystemProperties.getInt("ro.debuggable", 0) == 1);
-    private static final boolean VDBG = (PhoneApp.DBG_LEVEL >= 2);
+            (PhoneGlobals.DBG_LEVEL >= 1) && (SystemProperties.getInt("ro.debuggable", 0) == 1);
+    private static final boolean VDBG = (PhoneGlobals.DBG_LEVEL >= 2);
 
     // Maximum time we allow the CallerInfo query to run,
     // before giving up and falling back to the default ringtone.
@@ -148,10 +151,10 @@
     private static final int EMERGENCY_TONE_ALERT = 1;
     private static final int EMERGENCY_TONE_VIBRATE = 2;
 
-    private PhoneApp mApplication;
+    private PhoneGlobals mApplication;
     private CallManager mCM;
     private Ringer mRinger;
-    private BluetoothHandsfree mBluetoothHandsfree;
+    private BluetoothHeadset mBluetoothHeadset;
     private CallLogAsync mCallLog;
     private boolean mSilentRingerRequested;
 
@@ -183,11 +186,11 @@
      * Initialize the singleton CallNotifier instance.
      * This is only done once, at startup, from PhoneApp.onCreate().
      */
-    /* package */ static CallNotifier init(PhoneApp app, Phone phone, Ringer ringer,
-                                           BluetoothHandsfree btMgr, CallLogAsync callLog) {
+    /* package */ static CallNotifier init(PhoneGlobals app, Phone phone, Ringer ringer,
+                                           CallLogAsync callLog) {
         synchronized (CallNotifier.class) {
             if (sInstance == null) {
-                sInstance = new CallNotifier(app, phone, ringer, btMgr, callLog);
+                sInstance = new CallNotifier(app, phone, ringer, callLog);
             } else {
                 Log.wtf(LOG_TAG, "init() called multiple times!  sInstance = " + sInstance);
             }
@@ -196,8 +199,7 @@
     }
 
     /** Private constructor; @see init() */
-    private CallNotifier(PhoneApp app, Phone phone, Ringer ringer,
-                         BluetoothHandsfree btMgr, CallLogAsync callLog) {
+    private CallNotifier(PhoneGlobals app, Phone phone, Ringer ringer, CallLogAsync callLog) {
         mApplication = app;
         mCM = app.mCM;
         mCallLog = callLog;
@@ -220,7 +222,12 @@
         }
 
         mRinger = ringer;
-        mBluetoothHandsfree = btMgr;
+        BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
+        if (adapter != null) {
+            adapter.getProfileProxy(mApplication.getApplicationContext(),
+                                    mBluetoothProfileServiceListener,
+                                    BluetoothProfile.HEADSET);
+        }
 
         TelephonyManager telephonyManager = (TelephonyManager)app.getSystemService(
                 Context.TELEPHONY_SERVICE);
@@ -435,7 +442,7 @@
         // (This will be upgraded soon to a full wake lock; see
         // showIncomingCall().)
         if (VDBG) log("Holding wake lock on new incoming connection.");
-        mApplication.requestWakeState(PhoneApp.WakeState.PARTIAL);
+        mApplication.requestWakeState(PhoneGlobals.WakeState.PARTIAL);
 
         // - don't ring for call waiting connections
         // - do this before showing the incoming call panel
@@ -484,7 +491,7 @@
      */
     private boolean ignoreAllIncomingCalls(Phone phone) {
         // Incoming calls are totally ignored on non-voice-capable devices.
-        if (!PhoneApp.sVoiceCapable) {
+        if (!PhoneGlobals.sVoiceCapable) {
             // ...but still log a warning, since we shouldn't have gotten this
             // event in the first place!  (Incoming calls *should* be blocked at
             // the telephony layer on non-voice-capable capable devices.)
@@ -501,8 +508,8 @@
         }
 
         // Incoming calls are totally ignored if the device isn't provisioned yet.
-        boolean provisioned = Settings.Secure.getInt(mApplication.getContentResolver(),
-            Settings.Secure.DEVICE_PROVISIONED, 0) != 0;
+        boolean provisioned = Settings.Global.getInt(mApplication.getContentResolver(),
+            Settings.Global.DEVICE_PROVISIONED, 0) != 0;
         if (!provisioned) {
             Log.i(LOG_TAG, "Ignoring incoming call: not provisioned");
             return true;
@@ -701,34 +708,7 @@
         // Go directly to the in-call screen.
         // (No need to do anything special if we're already on the in-call
         // screen; it'll notice the phone state change and update itself.)
-
-        // But first, grab a full wake lock.  We do this here, before we
-        // even fire off the InCallScreen intent, to make sure the
-        // ActivityManager doesn't try to pause the InCallScreen as soon
-        // as it comes up.  (See bug 1648751.)
-        //
-        // And since the InCallScreen isn't visible yet (we haven't even
-        // fired off the intent yet), we DON'T want the screen to actually
-        // come on right now.  So *before* acquiring the wake lock we need
-        // to call preventScreenOn(), which tells the PowerManager that
-        // the screen should stay off even if someone's holding a full
-        // wake lock.  (This prevents any flicker during the "incoming
-        // call" sequence.  The corresponding preventScreenOn(false) call
-        // will come from the InCallScreen when it's finally ready to be
-        // displayed.)
-        //
-        // TODO: this is all a temporary workaround.  The real fix is to add
-        // an Activity attribute saying "this Activity wants to wake up the
-        // phone when it's displayed"; that way the ActivityManager could
-        // manage the wake locks *and* arrange for the screen to come on at
-        // the exact moment that the InCallScreen is ready to be displayed.
-        // (See bug 1648751.)
-        //
-        // TODO: also, we should probably *not* do any of this if the
-        // screen is already on(!)
-
-        mApplication.preventScreenOn(true);
-        mApplication.requestWakeState(PhoneApp.WakeState.FULL);
+        mApplication.requestWakeState(PhoneGlobals.WakeState.FULL);
 
         // Post the "incoming call" notification *and* include the
         // fullScreenIntent that'll launch the incoming-call UI.
@@ -797,8 +777,7 @@
             // if the call screen is showing, let it handle the event,
             // otherwise handle it here.
             if (!mApplication.isShowingCallScreen()) {
-                mApplication.setScreenTimeout(PhoneApp.ScreenTimeoutDuration.DEFAULT);
-                mApplication.requestWakeState(PhoneApp.WakeState.SLEEP);
+                mApplication.requestWakeState(PhoneGlobals.WakeState.SLEEP);
             }
 
             // Since we're now in-call, the Ringer should definitely *not*
@@ -842,9 +821,9 @@
                 }
 
                 if (callState == Call.State.DIALING || callState == Call.State.ALERTING) {
-                    mIsEmergencyToneOn = Settings.System.getInt(
+                    mIsEmergencyToneOn = Settings.Global.getInt(
                             mApplication.getContentResolver(),
-                            Settings.System.EMERGENCY_TONE, EMERGENCY_TONE_OFF);
+                            Settings.Global.EMERGENCY_TONE, EMERGENCY_TONE_OFF);
                     if (mIsEmergencyToneOn != EMERGENCY_TONE_OFF &&
                         mCurrentEmergencyToneState == EMERGENCY_TONE_OFF) {
                         if (mEmergencyTonePlayerVibrator != null) {
@@ -1033,8 +1012,8 @@
 
         int autoretrySetting = 0;
         if ((c != null) && (c.getCall().getPhone().getPhoneType() == PhoneConstants.PHONE_TYPE_CDMA)) {
-            autoretrySetting = android.provider.Settings.System.getInt(mApplication.
-                    getContentResolver(),android.provider.Settings.System.CALL_AUTO_RETRY, 0);
+            autoretrySetting = android.provider.Settings.Global.getInt(mApplication.
+                    getContentResolver(),android.provider.Settings.Global.CALL_AUTO_RETRY, 0);
         }
 
         // Stop any signalInfo tone being played when a call gets ended
@@ -1160,14 +1139,6 @@
             }
 
             mApplication.notificationMgr.cancelCallInProgressNotifications();
-
-            // If the screen is turned off when all the phone calls are hung up,
-            // InCallScreen#onDisconnect() will wake up the screen (only once) and let users
-            // check the disconnected status.
-            if (mApplication.isShowingCallScreen()) {
-                if (VDBG) log("onDisconnect: In call screen. Set short timeout.");
-                mApplication.clearUserActivityTimeout();
-            }
         }
 
         if (c != null) {
@@ -1292,8 +1263,8 @@
     private void resetAudioStateAfterDisconnect() {
         if (VDBG) log("resetAudioStateAfterDisconnect()...");
 
-        if (mBluetoothHandsfree != null) {
-            mBluetoothHandsfree.audioOff();
+        if (mBluetoothHeadset != null) {
+            mBluetoothHeadset.disconnectAudio();
         }
 
         // call turnOnSpeaker() with state=false and store=true even if speaker
@@ -1308,7 +1279,7 @@
 
         // "Voicemail" is meaningless on non-voice-capable devices,
         // so ignore MWI events.
-        if (!PhoneApp.sVoiceCapable) {
+        if (!PhoneGlobals.sVoiceCapable) {
             // ...but still log a warning, since we shouldn't have gotten this
             // event in the first place!
             // (PhoneStateListener.LISTEN_MESSAGE_WAITING_INDICATOR events
@@ -1528,8 +1499,8 @@
             ToneGenerator toneGenerator;
             try {
                 int stream;
-                if (mBluetoothHandsfree != null) {
-                    stream = mBluetoothHandsfree.isAudioOn() ? AudioManager.STREAM_BLUETOOTH_SCO:
+                if (mBluetoothHeadset != null) {
+                    stream = mBluetoothHeadset.isAudioOn() ? AudioManager.STREAM_BLUETOOTH_SCO:
                         AudioManager.STREAM_VOICE_CALL;
                 } else {
                     stream = AudioManager.STREAM_VOICE_CALL;
@@ -1694,7 +1665,7 @@
      */
     private void onSignalInfo(AsyncResult r) {
         // Signal Info are totally ignored on non-voice-capable devices.
-        if (!PhoneApp.sVoiceCapable) {
+        if (!PhoneGlobals.sVoiceCapable) {
             Log.w(LOG_TAG, "Got onSignalInfo() on non-voice-capable device! Ignoring...");
             return;
         }
@@ -1995,6 +1966,18 @@
         }
     }
 
+     private BluetoothProfile.ServiceListener mBluetoothProfileServiceListener =
+        new BluetoothProfile.ServiceListener() {
+        public void onServiceConnected(int profile, BluetoothProfile proxy) {
+            mBluetoothHeadset = (BluetoothHeadset) proxy;
+            if (VDBG) log("- Got BluetoothHeadset: " + mBluetoothHeadset);
+        }
+
+        public void onServiceDisconnected(int profile) {
+            mBluetoothHeadset = null;
+        }
+    };
+
     private void onRingbackTone(AsyncResult r) {
         boolean playTone = (Boolean)(r.result);
 
diff --git a/src/com/android/phone/CallTime.java b/src/com/android/phone/CallTime.java
index 39a69af..92c7972 100644
--- a/src/com/android/phone/CallTime.java
+++ b/src/com/android/phone/CallTime.java
@@ -195,7 +195,7 @@
             // For now, we move away from temp directory in favor of
             // the application's data directory to store the trace
             // information (/data/data/com.android.phone).
-            File file = PhoneApp.getInstance().getDir ("phoneTrace", Context.MODE_PRIVATE);
+            File file = PhoneGlobals.getInstance().getDir ("phoneTrace", Context.MODE_PRIVATE);
             if (file.exists() == false) {
                 file.mkdirs();
             }
diff --git a/src/com/android/phone/CallWaitingCheckBoxPreference.java b/src/com/android/phone/CallWaitingCheckBoxPreference.java
index 6394ff1..a2f5c70 100644
--- a/src/com/android/phone/CallWaitingCheckBoxPreference.java
+++ b/src/com/android/phone/CallWaitingCheckBoxPreference.java
@@ -17,7 +17,7 @@
 
 public class CallWaitingCheckBoxPreference extends CheckBoxPreference {
     private static final String LOG_TAG = "CallWaitingCheckBoxPreference";
-    private final boolean DBG = (PhoneApp.DBG_LEVEL >= 2);
+    private final boolean DBG = (PhoneGlobals.DBG_LEVEL >= 2);
 
     private final MyHandler mHandler = new MyHandler();
     private final Phone mPhone;
@@ -26,7 +26,7 @@
     public CallWaitingCheckBoxPreference(Context context, AttributeSet attrs, int defStyle) {
         super(context, attrs, defStyle);
 
-        mPhone = PhoneApp.getPhone();
+        mPhone = PhoneGlobals.getPhone();
     }
 
     public CallWaitingCheckBoxPreference(Context context, AttributeSet attrs) {
diff --git a/src/com/android/phone/CallerInfoCache.java b/src/com/android/phone/CallerInfoCache.java
index dc6ffae..76f79af 100644
--- a/src/com/android/phone/CallerInfoCache.java
+++ b/src/com/android/phone/CallerInfoCache.java
@@ -45,7 +45,7 @@
 public class CallerInfoCache {
     private static final String LOG_TAG = CallerInfoCache.class.getSimpleName();
     private static final boolean DBG =
-            (PhoneApp.DBG_LEVEL >= 1) && (SystemProperties.getInt("ro.debuggable", 0) == 1);
+            (PhoneGlobals.DBG_LEVEL >= 1) && (SystemProperties.getInt("ro.debuggable", 0) == 1);
 
     /** This must not be set to true when submitting changes. */
     private static final boolean VDBG = false;
diff --git a/src/com/android/phone/CallerInfoCacheUpdateReceiver.java b/src/com/android/phone/CallerInfoCacheUpdateReceiver.java
index 5d60947..c0a2d83 100644
--- a/src/com/android/phone/CallerInfoCacheUpdateReceiver.java
+++ b/src/com/android/phone/CallerInfoCacheUpdateReceiver.java
@@ -31,7 +31,7 @@
 public class CallerInfoCacheUpdateReceiver extends BroadcastReceiver {
     private static final String LOG_TAG = CallerInfoCacheUpdateReceiver.class.getSimpleName();
     private static final boolean DBG =
-            (PhoneApp.DBG_LEVEL >= 1) && (SystemProperties.getInt("ro.debuggable", 0) == 1);
+            (PhoneGlobals.DBG_LEVEL >= 1) && (SystemProperties.getInt("ro.debuggable", 0) == 1);
 
     public static final String ACTION_UPDATE_CALLER_INFO_CACHE =
             "com.android.phone.UPDATE_CALLER_INFO_CACHE";
@@ -39,7 +39,7 @@
     @Override
     public void onReceive(Context context, Intent intent) {
         if (DBG) log("CallerInfoCacheUpdateReceiver#onReceive(). Intent: " + intent);
-        PhoneApp.getInstance().callerInfoCache.startAsyncCache();
+        PhoneGlobals.getInstance().callerInfoCache.startAsyncCache();
     }
 
     private static void log(String msg) {
diff --git a/src/com/android/phone/CdmaCallOptions.java b/src/com/android/phone/CdmaCallOptions.java
index 656863b..8eecd27 100644
--- a/src/com/android/phone/CdmaCallOptions.java
+++ b/src/com/android/phone/CdmaCallOptions.java
@@ -32,7 +32,7 @@
 
 public class CdmaCallOptions extends PreferenceActivity {
     private static final String LOG_TAG = "CdmaCallOptions";
-    private final boolean DBG = (PhoneApp.DBG_LEVEL >= 2);
+    private final boolean DBG = (PhoneGlobals.DBG_LEVEL >= 2);
 
     private static final String BUTTON_VP_KEY = "button_voice_privacy_key";
     private CheckBoxPreference mButtonVoicePrivacy;
@@ -44,7 +44,7 @@
         addPreferencesFromResource(R.xml.cdma_call_privacy);
 
         mButtonVoicePrivacy = (CheckBoxPreference) findPreference(BUTTON_VP_KEY);
-        if (PhoneApp.getPhone().getPhoneType() != PhoneConstants.PHONE_TYPE_CDMA
+        if (PhoneGlobals.getPhone().getPhoneType() != PhoneConstants.PHONE_TYPE_CDMA
                 || getResources().getBoolean(R.bool.config_voice_privacy_disable)) {
             //disable the entire screen
             getPreferenceScreen().setEnabled(false);
diff --git a/src/com/android/phone/CdmaDisplayInfo.java b/src/com/android/phone/CdmaDisplayInfo.java
index 1e7dee8..1a88333 100755
--- a/src/com/android/phone/CdmaDisplayInfo.java
+++ b/src/com/android/phone/CdmaDisplayInfo.java
@@ -63,7 +63,7 @@
                 WindowManager.LayoutParams.FLAG_DIM_BEHIND);
 
         sDisplayInfoDialog.show();
-        PhoneApp.getInstance().wakeUpScreen();
+        PhoneGlobals.getInstance().wakeUpScreen();
 
     }
 
diff --git a/src/com/android/phone/CdmaSubscriptionListPreference.java b/src/com/android/phone/CdmaSubscriptionListPreference.java
index 43d3c0b..9b96850 100644
--- a/src/com/android/phone/CdmaSubscriptionListPreference.java
+++ b/src/com/android/phone/CdmaSubscriptionListPreference.java
@@ -22,6 +22,7 @@
 import android.os.Handler;
 import android.os.Message;
 import android.preference.ListPreference;
+import android.provider.Settings;
 import android.provider.Settings.Secure;
 import android.util.AttributeSet;
 import android.util.Log;
@@ -53,8 +54,8 @@
     }
 
     private void setCurrentCdmaSubscriptionModeValue() {
-        int cdmaSubscriptionMode = Secure.getInt(mPhone.getContext().getContentResolver(),
-                android.provider.Settings.Secure.CDMA_SUBSCRIPTION_MODE, preferredSubscriptionMode);
+        int cdmaSubscriptionMode = Settings.Global.getInt(mPhone.getContext().getContentResolver(),
+                Settings.Global.CDMA_SUBSCRIPTION_MODE, preferredSubscriptionMode);
         setValue(Integer.toString(cdmaSubscriptionMode));
     }
 
@@ -120,8 +121,8 @@
             if (ar.exception == null) {
                 // Get the original string entered by the user
                 int cdmaSubscriptionMode = Integer.valueOf((String) ar.userObj).intValue();
-                Secure.putInt(mPhone.getContext().getContentResolver(),
-                        Secure.CDMA_SUBSCRIPTION_MODE,
+                Settings.Global.putInt(mPhone.getContext().getContentResolver(),
+                        Settings.Global.CDMA_SUBSCRIPTION_MODE,
                         cdmaSubscriptionMode );
             } else {
                 Log.e(LOG_TAG, "Setting Cdma subscription source failed");
diff --git a/src/com/android/phone/CdmaSystemSelectListPreference.java b/src/com/android/phone/CdmaSystemSelectListPreference.java
index 7bbe008..d291fd7 100644
--- a/src/com/android/phone/CdmaSystemSelectListPreference.java
+++ b/src/com/android/phone/CdmaSystemSelectListPreference.java
@@ -23,6 +23,7 @@
 import android.os.Handler;
 import android.os.Message;
 import android.preference.ListPreference;
+import android.provider.Settings;
 import android.provider.Settings.Secure;
 import android.util.AttributeSet;
 import android.util.Log;
@@ -41,7 +42,7 @@
     public CdmaSystemSelectListPreference(Context context, AttributeSet attrs) {
         super(context, attrs);
 
-        mPhone = PhoneApp.getPhone();
+        mPhone = PhoneGlobals.getPhone();
         mHandler = new MyHandler();
         mPhone.queryCdmaRoamingPreference(
                 mHandler.obtainMessage(MyHandler.MESSAGE_GET_ROAMING_PREFERENCE));
@@ -68,8 +69,8 @@
         if (positiveResult && (getValue() != null)) {
             int buttonCdmaRoamingMode = Integer.valueOf(getValue()).intValue();
             int settingsCdmaRoamingMode =
-                    Secure.getInt(mPhone.getContext().getContentResolver(),
-                    Secure.CDMA_ROAMING_MODE, Phone.CDMA_RM_HOME);
+                    Settings.Global.getInt(mPhone.getContext().getContentResolver(),
+                    Settings.Global.CDMA_ROAMING_MODE, Phone.CDMA_RM_HOME);
             if (buttonCdmaRoamingMode != settingsCdmaRoamingMode) {
                 int statusCdmaRoamingMode;
                 switch(buttonCdmaRoamingMode) {
@@ -81,8 +82,8 @@
                         statusCdmaRoamingMode = Phone.CDMA_RM_HOME;
                 }
                 //Set the Settings.Secure network mode
-                Secure.putInt(mPhone.getContext().getContentResolver(),
-                        Secure.CDMA_ROAMING_MODE,
+                Settings.Global.putInt(mPhone.getContext().getContentResolver(),
+                        Settings.Global.CDMA_ROAMING_MODE,
                         buttonCdmaRoamingMode );
                 //Set the roaming preference mode
                 mPhone.setCdmaRoamingPreference(statusCdmaRoamingMode, mHandler
@@ -117,9 +118,9 @@
 
             if (ar.exception == null) {
                 int statusCdmaRoamingMode = ((int[])ar.result)[0];
-                int settingsRoamingMode = Secure.getInt(
+                int settingsRoamingMode = Settings.Global.getInt(
                         mPhone.getContext().getContentResolver(),
-                        Secure.CDMA_ROAMING_MODE, Phone.CDMA_RM_HOME);
+                        Settings.Global.CDMA_ROAMING_MODE, Phone.CDMA_RM_HOME);
                 //check that statusCdmaRoamingMode is from an accepted value
                 if (statusCdmaRoamingMode == Phone.CDMA_RM_HOME ||
                         statusCdmaRoamingMode == Phone.CDMA_RM_ANY ) {
@@ -127,9 +128,9 @@
                     if (statusCdmaRoamingMode != settingsRoamingMode) {
                         settingsRoamingMode = statusCdmaRoamingMode;
                         //changes the Settings.Secure accordingly to statusCdmaRoamingMode
-                        Secure.putInt(
+                        Settings.Global.putInt(
                                 mPhone.getContext().getContentResolver(),
-                                Secure.CDMA_ROAMING_MODE,
+                                Settings.Global.CDMA_ROAMING_MODE,
                                 settingsRoamingMode );
                     }
                     //changes the mButtonPreferredNetworkMode accordingly to modemNetworkMode
@@ -147,8 +148,8 @@
 
             if ((ar.exception == null) && (getValue() != null)) {
                 int cdmaRoamingMode = Integer.valueOf(getValue()).intValue();
-                Secure.putInt(mPhone.getContext().getContentResolver(),
-                        Secure.CDMA_ROAMING_MODE,
+                Settings.Global.putInt(mPhone.getContext().getContentResolver(),
+                        Settings.Global.CDMA_ROAMING_MODE,
                         cdmaRoamingMode );
             } else {
                 mPhone.queryCdmaRoamingPreference(obtainMessage(MESSAGE_GET_ROAMING_PREFERENCE));
@@ -159,8 +160,8 @@
             //set the mButtonCdmaRoam
             setValue(Integer.toString(Phone.CDMA_RM_HOME));
             //set the Settings.System
-            Secure.putInt(mPhone.getContext().getContentResolver(),
-                        Secure.CDMA_ROAMING_MODE,
+            Settings.Global.putInt(mPhone.getContext().getContentResolver(),
+                        Settings.Global.CDMA_ROAMING_MODE,
                         Phone.CDMA_RM_HOME );
             //Set the Status
             mPhone.setCdmaRoamingPreference(Phone.CDMA_RM_HOME,
diff --git a/src/com/android/phone/CdmaVoicePrivacyCheckBoxPreference.java b/src/com/android/phone/CdmaVoicePrivacyCheckBoxPreference.java
index 6439c67..a5ff37e 100644
--- a/src/com/android/phone/CdmaVoicePrivacyCheckBoxPreference.java
+++ b/src/com/android/phone/CdmaVoicePrivacyCheckBoxPreference.java
@@ -28,7 +28,7 @@
 
 public class CdmaVoicePrivacyCheckBoxPreference extends CheckBoxPreference {
     private static final String LOG_TAG = "CdmaVoicePrivacyCheckBoxPreference";
-    private final boolean DBG = (PhoneApp.DBG_LEVEL >= 2);
+    private final boolean DBG = (PhoneGlobals.DBG_LEVEL >= 2);
 
     Phone phone;
     private MyHandler mHandler = new MyHandler();
@@ -36,7 +36,7 @@
     public CdmaVoicePrivacyCheckBoxPreference(Context context, AttributeSet attrs, int defStyle) {
         super(context, attrs, defStyle);
 
-        phone = PhoneApp.getPhone();
+        phone = PhoneGlobals.getPhone();
         phone.getEnhancedVoicePrivacy(mHandler.obtainMessage(MyHandler.MESSAGE_GET_VP));
     }
 
diff --git a/src/com/android/phone/CellBroadcastSms.java b/src/com/android/phone/CellBroadcastSms.java
index 296fb69..7428321 100644
--- a/src/com/android/phone/CellBroadcastSms.java
+++ b/src/com/android/phone/CellBroadcastSms.java
@@ -183,15 +183,15 @@
             if(mButtonBcSms.isChecked()) {
                 mPhone.activateCellBroadcastSms(RILConstants.CDMA_CELL_BROADCAST_SMS_ENABLED,
                         Message.obtain(mHandler, MESSAGE_ACTIVATE_CB_SMS));
-                android.provider.Settings.Secure.putInt(mPhone.getContext().getContentResolver(),
-                        android.provider.Settings.Secure.CDMA_CELL_BROADCAST_SMS,
+                android.provider.Settings.Global.putInt(mPhone.getContext().getContentResolver(),
+                        android.provider.Settings.Global.CDMA_CELL_BROADCAST_SMS,
                         RILConstants.CDMA_CELL_BROADCAST_SMS_ENABLED);
                 enableDisableAllCbConfigButtons(true);
             } else {
                 mPhone.activateCellBroadcastSms(RILConstants.CDMA_CELL_BROADCAST_SMS_DISABLED,
                         Message.obtain(mHandler, MESSAGE_ACTIVATE_CB_SMS));
-                android.provider.Settings.Secure.putInt(mPhone.getContext().getContentResolver(),
-                        android.provider.Settings.Secure.CDMA_CELL_BROADCAST_SMS,
+                android.provider.Settings.Global.putInt(mPhone.getContext().getContentResolver(),
+                        android.provider.Settings.Global.CDMA_CELL_BROADCAST_SMS,
                         RILConstants.CDMA_CELL_BROADCAST_SMS_DISABLED);
                 enableDisableAllCbConfigButtons(false);
             }
@@ -337,7 +337,7 @@
 
         addPreferencesFromResource(R.xml.cell_broadcast_sms);
 
-        mPhone = PhoneApp.getPhone();
+        mPhone = PhoneGlobals.getPhone();
         mHandler = new MyHandler();
 
         PreferenceScreen prefSet = getPreferenceScreen();
@@ -422,9 +422,9 @@
 
         getPreferenceScreen().setEnabled(true);
 
-        int settingCbSms = android.provider.Settings.Secure.getInt(
+        int settingCbSms = android.provider.Settings.Global.getInt(
                 mPhone.getContext().getContentResolver(),
-                android.provider.Settings.Secure.CDMA_CELL_BROADCAST_SMS,
+                android.provider.Settings.Global.CDMA_CELL_BROADCAST_SMS,
                 RILConstants.CDMA_CELL_BROADCAST_SMS_DISABLED);
         mButtonBcSms.setChecked(settingCbSms == RILConstants.CDMA_CELL_BROADCAST_SMS_ENABLED);
 
@@ -547,8 +547,8 @@
                     mButtonBcSms.setChecked(false);
                     mPhone.activateCellBroadcastSms(RILConstants.CDMA_CELL_BROADCAST_SMS_DISABLED,
                             Message.obtain(mHandler, MESSAGE_ACTIVATE_CB_SMS));
-                    android.provider.Settings.Secure.putInt(mPhone.getContext().getContentResolver(),
-                            android.provider.Settings.Secure.CDMA_CELL_BROADCAST_SMS,
+                    android.provider.Settings.Global.putInt(mPhone.getContext().getContentResolver(),
+                            android.provider.Settings.Global.CDMA_CELL_BROADCAST_SMS,
                             RILConstants.CDMA_CELL_BROADCAST_SMS_DISABLED);
                     enableDisableAllCbConfigButtons(false);
                 }
diff --git a/src/com/android/phone/ChangeIccPinScreen.java b/src/com/android/phone/ChangeIccPinScreen.java
index 7a77294..70bf431 100644
--- a/src/com/android/phone/ChangeIccPinScreen.java
+++ b/src/com/android/phone/ChangeIccPinScreen.java
@@ -42,7 +42,7 @@
  * "Change ICC PIN" UI for the Phone app.
  */
 public class ChangeIccPinScreen extends Activity {
-    private static final String LOG_TAG = PhoneApp.LOG_TAG;
+    private static final String LOG_TAG = PhoneGlobals.LOG_TAG;
     private static final boolean DBG = false;
 
     private static final int EVENT_PIN_CHANGED = 100;
@@ -91,7 +91,7 @@
     public void onCreate(Bundle icicle) {
         super.onCreate(icicle);
 
-        mPhone = PhoneApp.getPhone();
+        mPhone = PhoneGlobals.getPhone();
 
         resolveIntent();
 
diff --git a/src/com/android/phone/ClearMissedCallsService.java b/src/com/android/phone/ClearMissedCallsService.java
index c9608b8..b882472 100644
--- a/src/com/android/phone/ClearMissedCallsService.java
+++ b/src/com/android/phone/ClearMissedCallsService.java
@@ -29,7 +29,7 @@
     public static final String ACTION_CLEAR_MISSED_CALLS =
             "com.android.phone.intent.CLEAR_MISSED_CALLS";
 
-    private PhoneApp mApp;
+    private PhoneGlobals mApp;
 
     public ClearMissedCallsService() {
         super(ClearMissedCallsService.class.getSimpleName());
@@ -38,7 +38,7 @@
     @Override
     public void onCreate() {
         super.onCreate();
-        mApp = PhoneApp.getInstance();
+        mApp = PhoneGlobals.getInstance();
     }
 
     @Override
diff --git a/src/com/android/phone/DTMFTwelveKeyDialer.java b/src/com/android/phone/DTMFTwelveKeyDialer.java
index c47b366..0f198f2 100644
--- a/src/com/android/phone/DTMFTwelveKeyDialer.java
+++ b/src/com/android/phone/DTMFTwelveKeyDialer.java
@@ -16,6 +16,7 @@
 
 package com.android.phone;
 
+import android.content.Context;
 import android.media.AudioManager;
 import android.media.ToneGenerator;
 import android.os.Handler;
@@ -30,6 +31,9 @@
 import android.view.KeyEvent;
 import android.view.MotionEvent;
 import android.view.View;
+import android.view.ViewConfiguration;
+import android.view.View.OnHoverListener;
+import android.view.accessibility.AccessibilityManager;
 import android.view.ViewStub;
 import android.widget.EditText;
 
@@ -46,14 +50,18 @@
  * Dialer class that encapsulates the DTMF twelve key behaviour.
  * This model backs up the UI behaviour in DTMFTwelveKeyDialerView.java.
  */
-public class DTMFTwelveKeyDialer implements View.OnTouchListener, View.OnKeyListener {
+public class DTMFTwelveKeyDialer implements View.OnTouchListener, View.OnKeyListener,
+        View.OnHoverListener, View.OnClickListener {
     private static final String LOG_TAG = "DTMFTwelveKeyDialer";
-    private static final boolean DBG = (PhoneApp.DBG_LEVEL >= 2);
+    private static final boolean DBG = (PhoneGlobals.DBG_LEVEL >= 2);
 
     // events
     private static final int PHONE_DISCONNECT = 100;
     private static final int DTMF_SEND_CNF = 101;
 
+    /** Accessibility manager instance used to check touch exploration state. */
+    private final AccessibilityManager mAccessibilityManager;
+
     private CallManager mCM;
     private ToneGenerator mToneGenerator;
     private final Object mToneGeneratorLock = new Object();
@@ -366,10 +374,7 @@
      */
     public DTMFTwelveKeyDialer(InCallScreen parent,
                                 DTMFTwelveKeyDialerView dialerView) {
-        if (DBG) log("DTMFTwelveKeyDialer constructor... this = " + this);
-
-        mInCallScreen = parent;
-        mCM = PhoneApp.getInstance().mCM;
+        this(parent);
 
         // The passed-in DTMFTwelveKeyDialerView *should* always be
         // non-null, now that the in-call UI uses only portrait mode.
@@ -398,10 +403,7 @@
      * {@link ViewStub#inflate()}.
      */
     public DTMFTwelveKeyDialer(InCallScreen parent, ViewStub dialerStub) {
-        if (DBG) log("DTMFTwelveKeyDialer constructor... this = " + this);
-
-        mInCallScreen = parent;
-        mCM = PhoneApp.getInstance().mCM;
+        this(parent);
 
         mDialerStub = dialerStub;
         if (DBG) log("- Got passed-in mDialerStub: " + mDialerStub);
@@ -410,6 +412,21 @@
     }
 
     /**
+     * Private constructor used for initialization calls common to all public
+     * constructors.
+     *
+     * @param parent the InCallScreen instance that owns us.
+     */
+    private DTMFTwelveKeyDialer(InCallScreen parent) {
+        if (DBG) log("DTMFTwelveKeyDialer constructor... this = " + this);
+
+        mInCallScreen = parent;
+        mCM = PhoneGlobals.getInstance().mCM;
+        mAccessibilityManager = (AccessibilityManager) parent.getSystemService(
+                Context.ACCESSIBILITY_SERVICE);
+    }
+
+    /**
      * Prepare the dialer view and relevant variables.
      */
     private void setupDialerView() {
@@ -467,7 +484,7 @@
 
         // On some devices the screen timeout is set to a special value
         // while the dialpad is up.
-        PhoneApp.getInstance().updateWakeState();
+        PhoneGlobals.getInstance().updateWakeState();
 
         // Give the InCallScreen a chance to do any necessary UI updates.
         if (mInCallScreen != null) {
@@ -493,7 +510,7 @@
         if (DBG) log("startDialerSession()... this = " + this);
 
         // see if we need to play local tones.
-        if (PhoneApp.getInstance().getResources().getBoolean(R.bool.allow_local_dtmf_tones)) {
+        if (PhoneGlobals.getInstance().getResources().getBoolean(R.bool.allow_local_dtmf_tones)) {
             mLocalToneEnabled = Settings.System.getInt(mInCallScreen.getContentResolver(),
                     Settings.System.DTMF_TONE_WHEN_DIALING, 1) == 1;
         } else {
@@ -526,7 +543,7 @@
         if (DBG) log("onDialerClose()...");
 
         // reset back to a short delay for the poke lock.
-        PhoneApp app = PhoneApp.getInstance();
+        PhoneGlobals app = PhoneGlobals.getInstance();
         app.updateWakeState();
 
         mCM.unregisterForDisconnect(mHandler);
@@ -593,6 +610,8 @@
             button.setOnTouchListener(this);
             button.setClickable(true);
             button.setOnKeyListener(this);
+            button.setOnHoverListener(this);
+            button.setOnClickListener(this);
         }
     }
 
@@ -621,6 +640,53 @@
     }
 
     /**
+     * Implemented for {@link android.view.View.OnHoverListener}. Handles touch
+     * events for accessibility when touch exploration is enabled.
+     */
+    @Override
+    public boolean onHover(View v, MotionEvent event) {
+        // When touch exploration is turned on, lifting a finger while inside
+        // the button's hover target bounds should perform a click action.
+        if (mAccessibilityManager.isEnabled()
+                && mAccessibilityManager.isTouchExplorationEnabled()) {
+            final int left = v.getPaddingLeft();
+            final int right = (v.getWidth() - v.getPaddingRight());
+            final int top = v.getPaddingTop();
+            final int bottom = (v.getHeight() - v.getPaddingBottom());
+
+            switch (event.getActionMasked()) {
+                case MotionEvent.ACTION_HOVER_ENTER:
+                    // Lift-to-type temporarily disables double-tap activation.
+                    v.setClickable(false);
+                    break;
+                case MotionEvent.ACTION_HOVER_EXIT:
+                    final int x = (int) event.getX();
+                    final int y = (int) event.getY();
+                    if ((x > left) && (x < right) && (y > top) && (y < bottom)) {
+                        v.performClick();
+                    }
+                    v.setClickable(true);
+                    break;
+            }
+        }
+
+        return false;
+    }
+
+    @Override
+    public void onClick(View v) {
+        // When accessibility is on, simulate press and release to preserve the
+        // semantic meaning of performClick(). Required for Braille support.
+        if (mAccessibilityManager.isEnabled()) {
+            final int id = v.getId();
+            // Checking the press state prevents double activation.
+            if (!v.isPressed() && mDisplayMap.containsKey(id)) {
+                processDtmf(mDisplayMap.get(id), true /* forceShortTone */);
+            }
+        }
+    }
+
+    /**
      * Implemented for the TouchListener, process the touch events.
      */
     @Override
@@ -764,8 +830,19 @@
      * Processes the specified digit as a DTMF key, by playing the
      * appropriate DTMF tone, and appending the digit to the EditText
      * field that displays the DTMF digits sent so far.
+     *
+     * @see #processDtmf(char, boolean)
      */
     private final void processDtmf(char c) {
+        processDtmf(c, false);
+    }
+
+    /**
+     * Processes the specified digit as a DTMF key, by playing the appropriate
+     * DTMF tone (or short tone if requested), and appending the digit to the
+     * EditText field that displays the DTMF digits sent so far.
+     */
+    private final void processDtmf(char c, boolean forceShortTone) {
         // if it is a valid key, then update the display and send the dtmf tone.
         if (PhoneNumberUtils.is12Key(c)) {
             if (DBG) log("updating display and sending dtmf tone for '" + c + "'");
@@ -787,14 +864,14 @@
             // Play the tone if it exists.
             if (mToneMap.containsKey(c)) {
                 // begin tone playback.
-                startTone(c);
+                startTone(c, forceShortTone);
             }
         } else if (DBG) {
             log("ignoring dtmf request for '" + c + "'");
         }
 
         // Any DTMF keypress counts as explicit "user activity".
-        PhoneApp.getInstance().pokeUserActivity();
+        PhoneGlobals.getInstance().pokeUserActivity();
     }
 
     /**
@@ -858,7 +935,7 @@
     /**
      * Plays the local tone based the phone type.
      */
-    public void startTone(char c) {
+    public void startTone(char c, boolean forceShortTone) {
         // Only play the tone if it exists.
         if (!mToneMap.containsKey(c)) {
             return;
@@ -875,20 +952,28 @@
         if (DBG) log("startDtmfTone()...");
 
         // For Short DTMF we need to play the local tone for fixed duration
-        if (mShortTone) {
+        if (forceShortTone || mShortTone) {
             sendShortDtmfToNetwork(c);
         } else {
             // Pass as a char to be sent to network
-            Log.i(LOG_TAG, "send long dtmf for " + c);
+            if (DBG) log("send long dtmf for " + c);
             mCM.startDtmf(c);
         }
-        startLocalToneIfNeeded(c);
+        startLocalToneIfNeeded(c, forceShortTone);
     }
 
     /**
      * Plays the local tone based the phone type.
      */
     public void startLocalToneIfNeeded(char c) {
+        startLocalToneIfNeeded(c, false);
+    }
+
+    /**
+     * Plays the local tone based the phone type, optionally forcing a short
+     * tone.
+     */
+    private void startLocalToneIfNeeded(char c, boolean forceShortTone) {
         // if local tone playback is enabled, start it.
         // Only play the tone if it exists.
         if (!mToneMap.containsKey(c)) {
@@ -901,7 +986,7 @@
                 } else {
                     if (DBG) log("starting local tone " + c);
                     int toneDuration = -1;
-                    if (mShortTone) {
+                    if (forceShortTone || mShortTone) {
                         toneDuration = DTMF_DURATION_MS;
                     }
                     mToneGenerator.startTone(mToneMap.get(c), toneDuration);
diff --git a/src/com/android/phone/DeleteFdnContactScreen.java b/src/com/android/phone/DeleteFdnContactScreen.java
index 19b10c6..074078c 100644
--- a/src/com/android/phone/DeleteFdnContactScreen.java
+++ b/src/com/android/phone/DeleteFdnContactScreen.java
@@ -36,7 +36,7 @@
  * Activity to let the user delete an FDN contact.
  */
 public class DeleteFdnContactScreen extends Activity {
-    private static final String LOG_TAG = PhoneApp.LOG_TAG;
+    private static final String LOG_TAG = PhoneGlobals.LOG_TAG;
     private static final boolean DBG = false;
 
     private static final String INTENT_EXTRA_NAME = "name";
diff --git a/src/com/android/phone/EditFdnContactScreen.java b/src/com/android/phone/EditFdnContactScreen.java
index 36a6b79..cca9a9f 100644
--- a/src/com/android/phone/EditFdnContactScreen.java
+++ b/src/com/android/phone/EditFdnContactScreen.java
@@ -51,7 +51,7 @@
  * Activity to let the user add or edit an FDN contact.
  */
 public class EditFdnContactScreen extends Activity {
-    private static final String LOG_TAG = PhoneApp.LOG_TAG;
+    private static final String LOG_TAG = PhoneGlobals.LOG_TAG;
     private static final boolean DBG = false;
 
     // Menu item codes
diff --git a/src/com/android/phone/EditPhoneNumberPreference.java b/src/com/android/phone/EditPhoneNumberPreference.java
index d5ef3a4..86671a8 100644
--- a/src/com/android/phone/EditPhoneNumberPreference.java
+++ b/src/com/android/phone/EditPhoneNumberPreference.java
@@ -260,7 +260,7 @@
             }
         }
         // set the call icon on the title.
-        builder.setIcon(R.drawable.ic_launcher_phone);
+        builder.setIcon(R.mipmap.ic_launcher_phone);
     }
 
 
diff --git a/src/com/android/phone/EmergencyCallHelper.java b/src/com/android/phone/EmergencyCallHelper.java
index 3508b94..7f5b0d2 100644
--- a/src/com/android/phone/EmergencyCallHelper.java
+++ b/src/com/android/phone/EmergencyCallHelper.java
@@ -29,6 +29,7 @@
 import android.os.Handler;
 import android.os.Message;
 import android.os.PowerManager;
+import android.os.UserHandle;
 import android.provider.Settings;
 import android.telephony.ServiceState;
 import android.util.Log;
@@ -65,7 +66,7 @@
     private static final int RETRY_TIMEOUT = 4;
 
     private CallController mCallController;
-    private PhoneApp mApp;
+    private PhoneGlobals mApp;
     private CallManager mCM;
     private Phone mPhone;
     private String mNumber;  // The emergency number we're trying to dial
@@ -77,7 +78,7 @@
     public EmergencyCallHelper(CallController callController) {
         if (DBG) log("EmergencyCallHelper constructor...");
         mCallController = callController;
-        mApp = PhoneApp.getInstance();
+        mApp = PhoneGlobals.getInstance();
         mCM =  mApp.mCM;
     }
 
@@ -346,18 +347,18 @@
 
         // If airplane mode is on, we turn it off the same way that the
         // Settings activity turns it off.
-        if (Settings.System.getInt(mApp.getContentResolver(),
-                                   Settings.System.AIRPLANE_MODE_ON, 0) > 0) {
+        if (Settings.Global.getInt(mApp.getContentResolver(),
+                                   Settings.Global.AIRPLANE_MODE_ON, 0) > 0) {
             if (DBG) log("==> Turning off airplane mode...");
 
             // Change the system setting
-            Settings.System.putInt(mApp.getContentResolver(),
-                                   Settings.System.AIRPLANE_MODE_ON, 0);
+            Settings.Global.putInt(mApp.getContentResolver(),
+                                   Settings.Global.AIRPLANE_MODE_ON, 0);
 
             // Post the intent
             Intent intent = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED);
             intent.putExtra("state", false);
-            mApp.sendBroadcast(intent);
+            mApp.sendBroadcastAsUser(intent, UserHandle.ALL);
         } else {
             // Otherwise, for some strange reason the radio is off
             // (even though the Settings database doesn't think we're
diff --git a/src/com/android/phone/EmergencyCallbackModeExitDialog.java b/src/com/android/phone/EmergencyCallbackModeExitDialog.java
index 2257aba..7758b23 100644
--- a/src/com/android/phone/EmergencyCallbackModeExitDialog.java
+++ b/src/com/android/phone/EmergencyCallbackModeExitDialog.java
@@ -91,7 +91,7 @@
         waitForConnectionCompleteThread.start();
 
         // Register ECM timer reset notfication
-        mPhone = PhoneApp.getPhone();
+        mPhone = PhoneGlobals.getPhone();
         mPhone.registerForEcmTimerReset(mTimerResetHandler, ECM_TIMER_RESET, null);
 
         // Register receiver for intent closing the dialog
diff --git a/src/com/android/phone/EmergencyDialer.java b/src/com/android/phone/EmergencyDialer.java
index a3c8d89..f3d9a14 100644
--- a/src/com/android/phone/EmergencyDialer.java
+++ b/src/com/android/phone/EmergencyDialer.java
@@ -37,8 +37,10 @@
 import android.text.method.DialerKeyListener;
 import android.util.Log;
 import android.view.KeyEvent;
+import android.view.MotionEvent;
 import android.view.View;
 import android.view.WindowManager;
+import android.view.accessibility.AccessibilityManager;
 import android.widget.EditText;
 
 
@@ -59,21 +61,28 @@
  * Or could we figure out some way to move *this* class into apps/Contacts
  * also?
  */
-public class EmergencyDialer extends Activity
-        implements View.OnClickListener, View.OnLongClickListener,
-        View.OnKeyListener, TextWatcher {
+public class EmergencyDialer extends Activity implements View.OnClickListener,
+        View.OnLongClickListener, View.OnHoverListener, View.OnKeyListener, TextWatcher {
     // Keys used with onSaveInstanceState().
     private static final String LAST_NUMBER = "lastNumber";
 
     // Intent action for this activity.
     public static final String ACTION_DIAL = "com.android.phone.EmergencyDialer.DIAL";
 
+    // List of dialer button IDs.
+    private static final int[] DIALER_KEYS = new int[] {
+            R.id.one, R.id.two, R.id.three,
+            R.id.four, R.id.five, R.id.six,
+            R.id.seven, R.id.eight, R.id.nine,
+            R.id.star, R.id.zero, R.id.pound };
+
     // Debug constants.
     private static final boolean DBG = false;
     private static final String LOG_TAG = "EmergencyDialer";
 
-    private PhoneApp mApp;
+    private PhoneGlobals mApp;
     private StatusBarManager mStatusBarManager;
+    private AccessibilityManager mAccessibilityManager;
 
     /** The length of DTMF tones in milliseconds */
     private static final int TONE_LENGTH_MS = 150;
@@ -86,6 +95,8 @@
 
     private static final int BAD_EMERGENCY_NUMBER_DIALOG = 0;
 
+    private static final int USER_ACTIVITY_TIMEOUT_WHEN_NO_PROX_SENSOR = 15000; // millis
+
     EditText mDigits;
     private View mDialButton;
     private View mDelete;
@@ -144,11 +155,18 @@
     protected void onCreate(Bundle icicle) {
         super.onCreate(icicle);
 
-        mApp = PhoneApp.getInstance();
+        mApp = PhoneGlobals.getInstance();
         mStatusBarManager = (StatusBarManager) getSystemService(Context.STATUS_BAR_SERVICE);
+        mAccessibilityManager = (AccessibilityManager) getSystemService(ACCESSIBILITY_SERVICE);
 
         // Allow this activity to be displayed in front of the keyguard / lockscreen.
-        getWindow().addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED);
+        WindowManager.LayoutParams lp = getWindow().getAttributes();
+        lp.flags |= WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED;
+        if (!mApp.proximitySensorModeEnabled()) {
+            // When no proximity sensor is available, use a shorter timeout.
+            lp.userActivityTimeout = USER_ACTIVITY_TIMEOUT_WHEN_NO_PROX_SENSOR;
+        }
+        getWindow().setAttributes(lp);
 
         setContentView(R.layout.emergency_dialer);
 
@@ -157,6 +175,10 @@
         mDigits.setOnClickListener(this);
         mDigits.setOnKeyListener(this);
         mDigits.setLongClickable(false);
+        if (mAccessibilityManager.isEnabled()) {
+            // The text view must be selected to send accessibility events.
+            mDigits.setSelected(true);
+        }
         maybeAddNumberFormatting();
 
         // Check for the presence of the keypad
@@ -260,22 +282,14 @@
 
     private void setupKeypad() {
         // Setup the listeners for the buttons
-        findViewById(R.id.one).setOnClickListener(this);
-        findViewById(R.id.two).setOnClickListener(this);
-        findViewById(R.id.three).setOnClickListener(this);
-        findViewById(R.id.four).setOnClickListener(this);
-        findViewById(R.id.five).setOnClickListener(this);
-        findViewById(R.id.six).setOnClickListener(this);
-        findViewById(R.id.seven).setOnClickListener(this);
-        findViewById(R.id.eight).setOnClickListener(this);
-        findViewById(R.id.nine).setOnClickListener(this);
-        findViewById(R.id.star).setOnClickListener(this);
+        for (int id : DIALER_KEYS) {
+            final View key = findViewById(id);
+            key.setOnClickListener(this);
+            key.setOnHoverListener(this);
+        }
 
         View view = findViewById(R.id.zero);
-        view.setOnClickListener(this);
         view.setOnLongClickListener(this);
-
-        findViewById(R.id.pound).setOnClickListener(this);
     }
 
     /**
@@ -405,6 +419,40 @@
     }
 
     /**
+     * Implemented for {@link android.view.View.OnHoverListener}. Handles touch
+     * events for accessibility when touch exploration is enabled.
+     */
+    @Override
+    public boolean onHover(View v, MotionEvent event) {
+        // When touch exploration is turned on, lifting a finger while inside
+        // the button's hover target bounds should perform a click action.
+        if (mAccessibilityManager.isEnabled()
+                && mAccessibilityManager.isTouchExplorationEnabled()) {
+
+            switch (event.getActionMasked()) {
+                case MotionEvent.ACTION_HOVER_ENTER:
+                    // Lift-to-type temporarily disables double-tap activation.
+                    v.setClickable(false);
+                    break;
+                case MotionEvent.ACTION_HOVER_EXIT:
+                    final int left = v.getPaddingLeft();
+                    final int right = (v.getWidth() - v.getPaddingRight());
+                    final int top = v.getPaddingTop();
+                    final int bottom = (v.getHeight() - v.getPaddingBottom());
+                    final int x = (int) event.getX();
+                    final int y = (int) event.getY();
+                    if ((x > left) && (x < right) && (y > top) && (y < bottom)) {
+                        v.performClick();
+                    }
+                    v.setClickable(true);
+                    break;
+            }
+        }
+
+        return false;
+    }
+
+    /**
      * called for long touch events
      */
     @Override
@@ -456,7 +504,6 @@
         // There is no need to do anything with the wake lock.
         if (DBG) Log.d(LOG_TAG, "disabling status bar, set to long timeout");
         mStatusBarManager.disable(StatusBarManager.DISABLE_EXPAND);
-        mApp.setScreenTimeout(PhoneApp.ScreenTimeoutDuration.MEDIUM);
 
         updateDialAndDeleteButtonStateEnabledAttr();
     }
@@ -467,7 +514,6 @@
         // There is no need to do anything with the wake lock.
         if (DBG) Log.d(LOG_TAG, "reenabling status bar and closing the dialer");
         mStatusBarManager.disable(StatusBarManager.DISABLE_NONE);
-        mApp.setScreenTimeout(PhoneApp.ScreenTimeoutDuration.DEFAULT);
 
         super.onPause();
 
diff --git a/src/com/android/phone/EnableFdnScreen.java b/src/com/android/phone/EnableFdnScreen.java
index 305407f..0db47c3 100644
--- a/src/com/android/phone/EnableFdnScreen.java
+++ b/src/com/android/phone/EnableFdnScreen.java
@@ -36,7 +36,7 @@
  * UI to enable/disable FDN.
  */
 public class EnableFdnScreen extends Activity {
-    private static final String LOG_TAG = PhoneApp.LOG_TAG;
+    private static final String LOG_TAG = PhoneGlobals.LOG_TAG;
     private static final boolean DBG = false;
 
     private static final int ENABLE_FDN_COMPLETE = 100;
@@ -67,7 +67,7 @@
         setContentView(R.layout.enable_fdn_screen);
         setupView();
 
-        mPhone = PhoneApp.getPhone();
+        mPhone = PhoneGlobals.getPhone();
         mEnable = !mPhone.getIccCard().getIccFdnEnabled();
 
         int id = mEnable ? R.string.enable_fdn : R.string.disable_fdn;
@@ -77,7 +77,7 @@
     @Override
     protected void onResume() {
         super.onResume();
-        mPhone = PhoneApp.getPhone();
+        mPhone = PhoneGlobals.getPhone();
     }
 
     private void setupView() {
diff --git a/src/com/android/phone/EnableIccPinScreen.java b/src/com/android/phone/EnableIccPinScreen.java
index a623d46..160978f 100644
--- a/src/com/android/phone/EnableIccPinScreen.java
+++ b/src/com/android/phone/EnableIccPinScreen.java
@@ -36,7 +36,7 @@
  * UI to enable/disable the ICC PIN.
  */
 public class EnableIccPinScreen extends Activity {
-    private static final String LOG_TAG = PhoneApp.LOG_TAG;
+    private static final String LOG_TAG = PhoneGlobals.LOG_TAG;
 
     private static final int ENABLE_ICC_PIN_COMPLETE = 100;
     private static final boolean DBG = false;
@@ -67,7 +67,7 @@
         setContentView(R.layout.enable_sim_pin_screen);
         setupView();
 
-        mPhone = PhoneApp.getPhone();
+        mPhone = PhoneGlobals.getPhone();
         mEnable = !mPhone.getIccCard().getIccLockEnabled();
 
         int id = mEnable ? R.string.enable_sim_pin : R.string.disable_sim_pin;
diff --git a/src/com/android/phone/FakePhoneActivity.java b/src/com/android/phone/FakePhoneActivity.java
index 07fce9c..686a766 100644
--- a/src/com/android/phone/FakePhoneActivity.java
+++ b/src/com/android/phone/FakePhoneActivity.java
@@ -54,10 +54,10 @@
                     }
                 });
 
-        mRadioControl = PhoneApp.getPhone().getSimulatedRadioControl();
+        mRadioControl = PhoneGlobals.getPhone().getSimulatedRadioControl();
 
-        Log.i(TAG, "- PhoneApp.getInstance(): " + PhoneApp.getInstance());
-        Log.i(TAG, "- PhoneApp.getPhone(): " + PhoneApp.getPhone());
+        Log.i(TAG, "- PhoneApp.getInstance(): " + PhoneGlobals.getInstance());
+        Log.i(TAG, "- PhoneApp.getPhone(): " + PhoneGlobals.getPhone());
         Log.i(TAG, "- mRadioControl: " + mRadioControl);
     }
 
diff --git a/src/com/android/phone/FdnSetting.java b/src/com/android/phone/FdnSetting.java
index 4f21e2f..283d612 100644
--- a/src/com/android/phone/FdnSetting.java
+++ b/src/com/android/phone/FdnSetting.java
@@ -40,7 +40,7 @@
 public class FdnSetting extends PreferenceActivity
         implements EditPinPreference.OnPinEnteredListener, DialogInterface.OnCancelListener {
 
-    private static final String LOG_TAG = PhoneApp.LOG_TAG;
+    private static final String LOG_TAG = PhoneGlobals.LOG_TAG;
     private static final boolean DBG = false;
 
     private Phone mPhone;
@@ -423,7 +423,7 @@
 
         addPreferencesFromResource(R.xml.fdn_setting);
 
-        mPhone = PhoneApp.getPhone();
+        mPhone = PhoneGlobals.getPhone();
 
         //get UI object references
         PreferenceScreen prefSet = getPreferenceScreen();
@@ -458,7 +458,7 @@
     @Override
     protected void onResume() {
         super.onResume();
-        mPhone = PhoneApp.getPhone();
+        mPhone = PhoneGlobals.getPhone();
         updateEnableFDN();
     }
 
diff --git a/src/com/android/phone/GetPin2Screen.java b/src/com/android/phone/GetPin2Screen.java
index c3fda66..a06b0cf 100644
--- a/src/com/android/phone/GetPin2Screen.java
+++ b/src/com/android/phone/GetPin2Screen.java
@@ -34,7 +34,7 @@
  * Pin2 entry screen.
  */
 public class GetPin2Screen extends Activity implements TextView.OnEditorActionListener {
-    private static final String LOG_TAG = PhoneApp.LOG_TAG;
+    private static final String LOG_TAG = PhoneGlobals.LOG_TAG;
 
     private EditText mPin2Field;
     private Button mOkButton;
diff --git a/src/com/android/phone/GsmUmtsAdditionalCallOptions.java b/src/com/android/phone/GsmUmtsAdditionalCallOptions.java
index 131ffe5..cd400f9 100644
--- a/src/com/android/phone/GsmUmtsAdditionalCallOptions.java
+++ b/src/com/android/phone/GsmUmtsAdditionalCallOptions.java
@@ -13,7 +13,7 @@
 public class GsmUmtsAdditionalCallOptions extends
         TimeConsumingPreferenceActivity {
     private static final String LOG_TAG = "GsmUmtsAdditionalCallOptions";
-    private final boolean DBG = (PhoneApp.DBG_LEVEL >= 2);
+    private final boolean DBG = (PhoneGlobals.DBG_LEVEL >= 2);
 
     private static final String BUTTON_CLIR_KEY  = "button_clir_key";
     private static final String BUTTON_CW_KEY    = "button_cw_key";
diff --git a/src/com/android/phone/GsmUmtsCallForwardOptions.java b/src/com/android/phone/GsmUmtsCallForwardOptions.java
index 09459eb..5f68135 100644
--- a/src/com/android/phone/GsmUmtsCallForwardOptions.java
+++ b/src/com/android/phone/GsmUmtsCallForwardOptions.java
@@ -18,7 +18,7 @@
 
 public class GsmUmtsCallForwardOptions extends TimeConsumingPreferenceActivity {
     private static final String LOG_TAG = "GsmUmtsCallForwardOptions";
-    private final boolean DBG = (PhoneApp.DBG_LEVEL >= 2);
+    private final boolean DBG = (PhoneGlobals.DBG_LEVEL >= 2);
 
     private static final String NUM_PROJECTION[] = {Phone.NUMBER};
 
diff --git a/src/com/android/phone/GsmUmtsCallOptions.java b/src/com/android/phone/GsmUmtsCallOptions.java
index ed28be9..a9a1940 100644
--- a/src/com/android/phone/GsmUmtsCallOptions.java
+++ b/src/com/android/phone/GsmUmtsCallOptions.java
@@ -27,7 +27,7 @@
 
 public class GsmUmtsCallOptions extends PreferenceActivity {
     private static final String LOG_TAG = "GsmUmtsCallOptions";
-    private final boolean DBG = (PhoneApp.DBG_LEVEL >= 2);
+    private final boolean DBG = (PhoneGlobals.DBG_LEVEL >= 2);
 
     @Override
     protected void onCreate(Bundle icicle) {
@@ -35,7 +35,7 @@
 
         addPreferencesFromResource(R.xml.gsm_umts_call_options);
 
-        if (PhoneApp.getPhone().getPhoneType() != PhoneConstants.PHONE_TYPE_GSM) {
+        if (PhoneGlobals.getPhone().getPhoneType() != PhoneConstants.PHONE_TYPE_GSM) {
             //disable the entire screen
             getPreferenceScreen().setEnabled(false);
         }
diff --git a/src/com/android/phone/IccNetworkDepersonalizationPanel.java b/src/com/android/phone/IccNetworkDepersonalizationPanel.java
index 3688be2..aa582a1 100644
--- a/src/com/android/phone/IccNetworkDepersonalizationPanel.java
+++ b/src/com/android/phone/IccNetworkDepersonalizationPanel.java
@@ -39,7 +39,7 @@
 /**
  * "SIM network unlock" PIN entry screen.
  *
- * @see PhoneApp.EVENT_SIM_NETWORK_LOCKED
+ * @see PhoneGlobals.EVENT_SIM_NETWORK_LOCKED
  *
  * TODO: This UI should be part of the lock screen, not the
  * phone app (see bug 1804111).
@@ -148,7 +148,7 @@
         mStatusPanel = (LinearLayout) findViewById(R.id.status_panel);
         mStatusText = (TextView) findViewById(R.id.status_text);
 
-        mPhone = PhoneApp.getPhone();
+        mPhone = PhoneGlobals.getPhone();
     }
 
     @Override
diff --git a/src/com/android/phone/IccPanel.java b/src/com/android/phone/IccPanel.java
index c80b5dc..e603a06 100644
--- a/src/com/android/phone/IccPanel.java
+++ b/src/com/android/phone/IccPanel.java
@@ -29,7 +29,7 @@
  * Base class for ICC-related panels in the Phone UI.
  */
 public class IccPanel extends Dialog {
-    protected static final String TAG = PhoneApp.LOG_TAG;
+    protected static final String TAG = PhoneGlobals.LOG_TAG;
 
     private StatusBarManager mStatusBarManager;
 
@@ -65,7 +65,7 @@
         // TODO: we shouldn't need the mStatusBarManager calls here either,
         // once this dialog gets moved into the framework and becomes a truly
         // full-screen UI.
-        PhoneApp app = PhoneApp.getInstance();
+        PhoneGlobals app = PhoneGlobals.getInstance();
         mStatusBarManager = (StatusBarManager) app.getSystemService(Context.STATUS_BAR_SERVICE);
 
         requestWindowFeature(Window.FEATURE_NO_TITLE);
diff --git a/src/com/android/phone/InCallControlState.java b/src/com/android/phone/InCallControlState.java
index e901cf1..e5c7f20 100644
--- a/src/com/android/phone/InCallControlState.java
+++ b/src/com/android/phone/InCallControlState.java
@@ -42,7 +42,7 @@
  */
 public class InCallControlState {
     private static final String LOG_TAG = "InCallControlState";
-    private static final boolean DBG = (PhoneApp.DBG_LEVEL >= 2);
+    private static final boolean DBG = (PhoneGlobals.DBG_LEVEL >= 2);
 
     private InCallScreen mInCallScreen;
     private CallManager mCM;
diff --git a/src/com/android/phone/InCallScreen.java b/src/com/android/phone/InCallScreen.java
index 05675e6..f8ba9c7 100755
--- a/src/com/android/phone/InCallScreen.java
+++ b/src/com/android/phone/InCallScreen.java
@@ -25,6 +25,7 @@
 import android.bluetooth.BluetoothDevice;
 import android.bluetooth.BluetoothHeadset;
 import android.bluetooth.BluetoothProfile;
+import android.bluetooth.IBluetoothHeadsetPhone;
 import android.content.ActivityNotFoundException;
 import android.content.BroadcastReceiver;
 import android.content.Context;
@@ -41,6 +42,7 @@
 import android.os.Handler;
 import android.os.Message;
 import android.os.PowerManager;
+import android.os.RemoteException;
 import android.os.SystemClock;
 import android.os.SystemProperties;
 import android.telephony.ServiceState;
@@ -83,8 +85,8 @@
     private static final String LOG_TAG = "InCallScreen";
 
     private static final boolean DBG =
-            (PhoneApp.DBG_LEVEL >= 1) && (SystemProperties.getInt("ro.debuggable", 0) == 1);
-    private static final boolean VDBG = (PhoneApp.DBG_LEVEL >= 2);
+            (PhoneGlobals.DBG_LEVEL >= 1) && (SystemProperties.getInt("ro.debuggable", 0) == 1);
+    private static final boolean VDBG = (PhoneGlobals.DBG_LEVEL >= 2);
 
     /**
      * Intent extra used to specify whether the DTMF dialpad should be
@@ -151,7 +153,6 @@
     private static final int DONT_ADD_VOICEMAIL_NUMBER = 107;
     private static final int DELAYED_CLEANUP_AFTER_DISCONNECT = 108;
     private static final int SUPP_SERVICE_FAILED = 110;
-    private static final int ALLOW_SCREEN_ON = 112;
     private static final int REQUEST_UPDATE_BLUETOOTH_INDICATION = 114;
     private static final int PHONE_CDMA_CALL_WAITING = 115;
     private static final int REQUEST_CLOSE_SPC_ERROR_NOTICE = 118;
@@ -187,7 +188,7 @@
 
     private boolean mRegisteredForPhoneStates;
 
-    private PhoneApp mApp;
+    private PhoneGlobals mApp;
     private CallManager mCM;
 
     // TODO: need to clean up all remaining uses of mPhone.
@@ -197,9 +198,8 @@
     // based on the current foreground Call.)
     private Phone mPhone;
 
-    private BluetoothHandsfree mBluetoothHandsfree;
     private BluetoothHeadset mBluetoothHeadset;
-    private BluetoothAdapter mAdapter;
+    private BluetoothAdapter mBluetoothAdapter;
     private boolean mBluetoothConnectionPending;
     private long mBluetoothConnectionRequestTime;
 
@@ -316,7 +316,7 @@
                 // onMMIInitiate((AsyncResult) msg.obj);
                 //    break;
 
-                case PhoneApp.MMI_CANCEL:
+                case PhoneGlobals.MMI_CANCEL:
                     onMMICancel();
                     break;
 
@@ -324,7 +324,7 @@
                 // since the message display class has been replaced with
                 // a system dialog in PhoneUtils.displayMMIComplete(), we
                 // should finish the activity here to close the window.
-                case PhoneApp.MMI_COMPLETE:
+                case PhoneGlobals.MMI_COMPLETE:
                     onMMIComplete((MmiCode) ((AsyncResult) msg.obj).result);
                     break;
 
@@ -344,15 +344,6 @@
                     delayedCleanupAfterDisconnect();
                     break;
 
-                case ALLOW_SCREEN_ON:
-                    if (VDBG) log("ALLOW_SCREEN_ON message...");
-                    // Undo our previous call to preventScreenOn(true).
-                    // (Note this will cause the screen to turn on
-                    // immediately, if it's currently off because of a
-                    // prior preventScreenOn(true) call.)
-                    mApp.preventScreenOn(false);
-                    break;
-
                 case REQUEST_UPDATE_BLUETOOTH_INDICATION:
                     if (VDBG) log("REQUEST_UPDATE_BLUETOOTH_INDICATION...");
                     // The bluetooth headset state changed, so some UI
@@ -448,7 +439,7 @@
         super.onCreate(icicle);
 
         // Make sure this is a voice-capable device.
-        if (!PhoneApp.sVoiceCapable) {
+        if (!PhoneGlobals.sVoiceCapable) {
             // There should be no way to ever reach the InCallScreen on a
             // non-voice-capable device, since this activity is not exported by
             // our manifest, and we explicitly disable any other external APIs
@@ -459,11 +450,12 @@
             return;
         }
 
-        mApp = PhoneApp.getInstance();
+        mApp = PhoneGlobals.getInstance();
         mApp.setInCallScreenInstance(this);
 
         // set this flag so this activity will stay in front of the keyguard
-        int flags = WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED;
+        int flags = WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
+                | WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON;
         if (mApp.getPhoneState() == PhoneConstants.State.OFFHOOK) {
             // While we are in call, the in-call screen should dismiss the keyguard.
             // This allows the user to press Home to go directly home without going through
@@ -472,24 +464,26 @@
             // bypass the keyguard if the call is not answered or declined.
             flags |= WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD;
         }
-        getWindow().addFlags(flags);
+
+        WindowManager.LayoutParams lp = getWindow().getAttributes();
+        lp.flags |= flags;
+        if (!mApp.proximitySensorModeEnabled()) {
+            // If we don't have a proximity sensor, then the in-call screen explicitly
+            // controls user activity.  This is to prevent spurious touches from waking
+            // the display.
+            lp.inputFeatures |= WindowManager.LayoutParams.INPUT_FEATURE_DISABLE_USER_ACTIVITY;
+        }
+        getWindow().setAttributes(lp);
 
         setPhone(mApp.phone);  // Sets mPhone
 
         mCM =  mApp.mCM;
         log("- onCreate: phone state = " + mCM.getState());
 
-        mBluetoothHandsfree = mApp.getBluetoothHandsfree();
-        if (VDBG) log("- mBluetoothHandsfree: " + mBluetoothHandsfree);
-
-        if (mBluetoothHandsfree != null) {
-            // The PhoneApp only creates a BluetoothHandsfree instance in the
-            // first place if BluetoothAdapter.getDefaultAdapter()
-            // succeeds.  So at this point we know the device is BT-capable.
-            mAdapter = BluetoothAdapter.getDefaultAdapter();
-            mAdapter.getProfileProxy(getApplicationContext(), mBluetoothProfileServiceListener,
+        mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
+        if (mBluetoothAdapter != null) {
+            mBluetoothAdapter.getProfileProxy(getApplicationContext(), mBluetoothProfileServiceListener,
                                     BluetoothProfile.HEADSET);
-
         }
 
         requestWindowFeature(Window.FEATURE_NO_TITLE);
@@ -497,6 +491,13 @@
         // Inflate everything in incall_screen.xml and add it to the screen.
         setContentView(R.layout.incall_screen);
 
+        // If in landscape, then one of the ViewStubs (instead of <include>) is used for the
+        // incall_touch_ui, because CDMA and GSM button layouts are noticeably different.
+        final ViewStub touchUiStub = (ViewStub) findViewById(
+                mPhone.getPhoneType() == PhoneConstants.PHONE_TYPE_CDMA
+                ? R.id.inCallTouchUiCdmaStub : R.id.inCallTouchUiStub);
+        if (touchUiStub != null) touchUiStub.inflate();
+
         initInCallScreen();
 
         registerForPhoneStates();
@@ -560,11 +561,6 @@
         final InCallUiState inCallUiState = mApp.inCallUiState;
         if (VDBG) inCallUiState.dumpState();
 
-        // Touch events are never considered "user activity" while the
-        // InCallScreen is active, so that unintentional touches won't
-        // prevent the device from going to sleep.
-        mApp.setIgnoreTouchUserActivity(true);
-
         updateExpandedViewState();
 
         // ...and update the in-call notification too, since the status bar
@@ -711,40 +707,6 @@
         // InCallScreen is now active.
         EventLog.writeEvent(EventLogTags.PHONE_UI_ENTER);
 
-        // Coming to the foreground while in an incoming call is ringing.
-        // We need to do something special.
-        if (mCM.getState() == PhoneConstants.State.RINGING) {
-            // If the phone is ringing, we *should* already be holding a
-            // full wake lock (which we would have acquired before
-            // firing off the intent that brought us here; see
-            // CallNotifier.showIncomingCall().)
-            //
-            // We also called preventScreenOn(true) at that point, to
-            // avoid cosmetic glitches while we were being launched.
-            // So now we need to post an ALLOW_SCREEN_ON message to
-            // (eventually) undo the prior preventScreenOn(true) call.
-            //
-            // (In principle we shouldn't do this until after our first
-            // layout/draw pass.  But in practice, the delay caused by
-            // simply waiting for the end of the message queue is long
-            // enough to avoid any flickering of the lock screen before
-            // the InCallScreen comes up.)
-            if (VDBG) log("- posting ALLOW_SCREEN_ON message...");
-            mHandler.removeMessages(ALLOW_SCREEN_ON);
-            mHandler.sendEmptyMessage(ALLOW_SCREEN_ON);
-
-            // TODO: There ought to be a more elegant way of doing this,
-            // probably by having the PowerManager and ActivityManager
-            // work together to let apps request that the screen on/off
-            // state be synchronized with the Activity lifecycle.
-            // (See bug 1648751.)
-        } else {
-            // The phone isn't ringing; this is either an outgoing call, or
-            // we're returning to a call in progress.  There *shouldn't* be
-            // any prior preventScreenOn(true) call that we need to undo,
-            // but let's do this just to be safe:
-            mApp.preventScreenOn(false);
-        }
         // Update the poke lock and wake lock when we move to the foreground.
         // This will be no-op when prox sensor is effective.
         mApp.updateWakeState();
@@ -779,7 +741,7 @@
         if (!mPhone.getPendingMmiCodes().isEmpty()) {
             if (mMmiStartedDialog == null) {
                 MmiCode mmiCode = mPhone.getPendingMmiCodes().get(0);
-                Message message = Message.obtain(mHandler, PhoneApp.MMI_CANCEL);
+                Message message = Message.obtain(mHandler, PhoneGlobals.MMI_CANCEL);
                 mMmiStartedDialog = PhoneUtils.displayMMIInitiate(this, mmiCode,
                         message, mMmiStartedDialog);
                 // mInCallScreen needs to receive MMI_COMPLETE/MMI_CANCEL event from telephony,
@@ -894,17 +856,6 @@
         // foreground.)
         unregisterReceiver(mReceiver);
 
-        // Re-enable "user activity" for touch events.
-        // We actually do this slightly *after* onPause(), to work around a
-        // race condition where a touch can come in after we've paused
-        // but before the device actually goes to sleep.
-        // TODO: The PowerManager itself should prevent this from happening.
-        mHandler.postDelayed(new Runnable() {
-                public void run() {
-                    mApp.setIgnoreTouchUserActivity(false);
-                }
-            }, 500);
-
         // Make sure we revert the poke lock and wake lock when we move to
         // the background.
         mApp.updateWakeState();
@@ -989,7 +940,7 @@
         // are moving out of the foreground.
 
         if (mBluetoothHeadset != null) {
-            mAdapter.closeProfileProxy(BluetoothProfile.HEADSET, mBluetoothHeadset);
+            mBluetoothAdapter.closeProfileProxy(BluetoothProfile.HEADSET, mBluetoothHeadset);
             mBluetoothHeadset = null;
         }
 
@@ -1099,7 +1050,7 @@
             // message display class in PhoneUtils.displayMMIComplete().
             // We'll listen for that message too, so that we can finish
             // the activity at the same time.
-            mCM.registerForMmiComplete(mHandler, PhoneApp.MMI_COMPLETE, null);
+            mCM.registerForMmiComplete(mHandler, PhoneGlobals.MMI_COMPLETE, null);
             mCM.registerForCallWaiting(mHandler, PHONE_CDMA_CALL_WAITING, null);
             mCM.registerForPostDialCharacter(mHandler, POST_ON_DIAL_CHARS, null);
             mCM.registerForSuppServiceFailed(mHandler, SUPP_SERVICE_FAILED, null);
@@ -1721,8 +1672,8 @@
             // Get the Auto-retry setting only if Phone State is IDLE,
             // else let it stay as AUTO_RETRY_OFF
             if (currentlyIdle) {
-                autoretrySetting = android.provider.Settings.System.getInt(mPhone.getContext().
-                        getContentResolver(), android.provider.Settings.System.CALL_AUTO_RETRY, 0);
+                autoretrySetting = android.provider.Settings.Global.getInt(mPhone.getContext().
+                        getContentResolver(), android.provider.Settings.Global.CALL_AUTO_RETRY, 0);
             }
         }
 
@@ -2685,7 +2636,7 @@
                 if ((mLastDisconnectCause != Connection.DisconnectCause.INCOMING_MISSED)
                         && (mLastDisconnectCause != Connection.DisconnectCause.INCOMING_REJECTED)
                         && !isPhoneStateRestricted()
-                        && PhoneApp.sVoiceCapable) {
+                        && PhoneGlobals.sVoiceCapable) {
                     final Intent intent = mApp.createPhoneEndIntentUsingCallOrigin();
                     ActivityOptions opts = ActivityOptions.makeCustomAnimation(this,
                             R.anim.activity_close_enter, R.anim.activity_close_exit);
@@ -2711,8 +2662,8 @@
                     // stay in the activity history.
                 }
 
-                endInCallScreenSession();
             }
+            endInCallScreenSession();
 
             // Reset the call origin when the session ends and this in-call UI is being finished.
             mApp.setLatestActiveCallOrigin(null);
@@ -3700,13 +3651,17 @@
         // multiple background calls, for now, always act on the first background calll.
         PhoneUtils.switchHoldingAndActive(mCM.getFirstActiveBgCall());
 
-        // If we have a valid BluetoothHandsfree then since CDMA network or
+        // If we have a valid BluetoothPhoneService then since CDMA network or
         // Telephony FW does not send us information on which caller got swapped
-        // we need to update the second call active state in BluetoothHandsfree internally
+        // we need to update the second call active state in BluetoothPhoneService internally
         if (mCM.getBgPhone().getPhoneType() == PhoneConstants.PHONE_TYPE_CDMA) {
-            BluetoothHandsfree bthf = mApp.getBluetoothHandsfree();
-            if (bthf != null) {
-                bthf.cdmaSwapSecondCallState();
+            IBluetoothHeadsetPhone btPhone = mApp.getBluetoothPhoneService();
+            if (btPhone != null) {
+                try {
+                    btPhone.cdmaSwapSecondCallState();
+                } catch (RemoteException e) {
+                    Log.e(LOG_TAG, Log.getStackTraceString(new Throwable()));
+                }
             }
         }
 
@@ -4117,13 +4072,6 @@
     //   headset (which we don't do from the Phone UI!) but also lets you
     //   get the address of the currently active headset and see whether
     //   it's currently connected.
-    //
-    // - BluetoothHandsfree is the API to control the audio connection to
-    //   a bluetooth headset. We use this API to switch the headset on and
-    //   off when the user presses the "Bluetooth" button.
-    //   Our BluetoothHandsfree instance (mBluetoothHandsfree) is created
-    //   by the PhoneApp and will be null if the device is not BT capable.
-    //
 
     /**
      * @return true if the Bluetooth on/off switch in the UI should be
@@ -4132,11 +4080,6 @@
      */
     /* package */ boolean isBluetoothAvailable() {
         if (VDBG) log("isBluetoothAvailable()...");
-        if (mBluetoothHandsfree == null) {
-            // Device is not BT capable.
-            if (VDBG) log("  ==> FALSE (not BT capable)");
-            return false;
-        }
 
         // There's no need to ask the Bluetooth system service if BT is enabled:
         //
@@ -4173,14 +4116,20 @@
     }
 
     /**
-     * @return true if a BT device is available, and its audio is currently connected.
+     * @return true if a BT Headset is available, and its audio is currently connected.
      */
     /* package */ boolean isBluetoothAudioConnected() {
-        if (mBluetoothHandsfree == null) {
-            if (VDBG) log("isBluetoothAudioConnected: ==> FALSE (null mBluetoothHandsfree)");
+        if (mBluetoothHeadset == null) {
+            if (VDBG) log("isBluetoothAudioConnected: ==> FALSE (null mBluetoothHeadset)");
             return false;
         }
-        boolean isAudioOn = mBluetoothHandsfree.isAudioOn();
+        List<BluetoothDevice> deviceList = mBluetoothHeadset.getConnectedDevices();
+
+        if (deviceList.isEmpty()) {
+            return false;
+        }
+        BluetoothDevice device = deviceList.get(0);
+        boolean isAudioOn = mBluetoothHeadset.isAudioConnected(device);
         if (VDBG) log("isBluetoothAudioConnected: ==> isAudioOn = " + isAudioOn);
         return isAudioOn;
     }
@@ -4190,7 +4139,7 @@
      * see InCallControlState.bluetoothIndicatorOn.
      *
      * @return true if a BT device is available and its audio is currently connected,
-     *              <b>or</b> if we issued a BluetoothHandsfree.userWantsAudioOn()
+     *              <b>or</b> if we issued a BluetoothHeadset.connectAudio()
      *              call within the last 5 seconds (which presumably means
      *              that the BT audio connection is currently being set
      *              up, and will be connected soon.)
@@ -4201,7 +4150,7 @@
             return true;
         }
 
-        // If we issued a userWantsAudioOn() call "recently enough", even
+        // If we issued a connectAudio() call "recently enough", even
         // if BT isn't actually connected yet, let's still pretend BT is
         // on.  This makes the onscreen indication more responsive.
         if (mBluetoothConnectionPending) {
@@ -4244,8 +4193,7 @@
         log("= PhoneApp.showBluetoothIndication: "
             + mApp.showBluetoothIndication());
         log("=");
-        if (mBluetoothHandsfree != null) {
-            log("= BluetoothHandsfree.isAudioOn: " + mBluetoothHandsfree.isAudioOn());
+        if (mBluetoothAdapter != null) {
             if (mBluetoothHeadset != null) {
                 List<BluetoothDevice> deviceList = mBluetoothHeadset.getConnectedDevices();
 
@@ -4254,23 +4202,26 @@
                     log("= BluetoothHeadset.getCurrentDevice: " + device);
                     log("= BluetoothHeadset.State: "
                         + mBluetoothHeadset.getConnectionState(device));
+                    log("= BluetoothHeadset audio connected: " +
+                        mBluetoothHeadset.isAudioConnected(device));
                 }
             } else {
                 log("= mBluetoothHeadset is null");
             }
         } else {
-            log("= mBluetoothHandsfree is null; device is not BT capable");
+            log("= mBluetoothAdapter is null; device is not BT capable");
         }
     }
 
     /* package */ void connectBluetoothAudio() {
         if (VDBG) log("connectBluetoothAudio()...");
-        if (mBluetoothHandsfree != null) {
-            mBluetoothHandsfree.userWantsAudioOn();
+        if (mBluetoothHeadset != null) {
+            // TODO(BT) check return
+            mBluetoothHeadset.connectAudio();
         }
 
         // Watch out: The bluetooth connection doesn't happen instantly;
-        // the userWantsAudioOn() call returns instantly but does its real
+        // the connectAudio() call returns instantly but does its real
         // work in another thread.  The mBluetoothConnectionPending flag
         // is just a little trickery to ensure that the onscreen UI updates
         // instantly. (See isBluetoothAudioConnectedOrPending() above.)
@@ -4280,8 +4231,8 @@
 
     /* package */ void disconnectBluetoothAudio() {
         if (VDBG) log("disconnectBluetoothAudio()...");
-        if (mBluetoothHandsfree != null) {
-            mBluetoothHandsfree.userWantsAudioOff();
+        if (mBluetoothHeadset != null) {
+            mBluetoothHeadset.disconnectAudio();
         }
         mBluetoothConnectionPending = false;
     }
@@ -4535,11 +4486,12 @@
     /**
      * Manually handle configuration changes.
      *
-     * We specify android:configChanges="orientation|keyboardHidden|uiMode" in
-     * our manifest to make sure the system doesn't destroy and re-create us
-     * due to the above config changes.  Instead, this method will be called,
-     * and should manually rebuild the onscreen UI to keep it in sync with the
-     * current configuration.
+     * Originally android:configChanges was set to "orientation|keyboardHidden|uiMode"
+     * in order "to make sure the system doesn't destroy and re-create us due to the
+     * above config changes". However it is currently set to "keyboardHidden" since
+     * the system needs to handle rotation when inserted into a compatible cardock.
+     * Even without explicitly handling orientation and uiMode, the app still runs
+     * and does not drop the call when rotated.
      *
      */
     public void onConfigurationChanged(Configuration newConfig) {
@@ -4652,4 +4604,11 @@
             log("Requested to remove provider info after " + PROVIDER_INFO_TIMEOUT + " msec.");
         }
     }
+
+    /**
+     * Indicates whether or not the QuickResponseDialog is currently showing in the call screen
+     */
+    public boolean isQuickResponseDialogShowing() {
+        return mRespondViaSmsManager != null && mRespondViaSmsManager.isShowingPopup();
+    }
 }
diff --git a/src/com/android/phone/InCallScreenShowActivation.java b/src/com/android/phone/InCallScreenShowActivation.java
index ad13186..221b915 100644
--- a/src/com/android/phone/InCallScreenShowActivation.java
+++ b/src/com/android/phone/InCallScreenShowActivation.java
@@ -42,7 +42,7 @@
 public class InCallScreenShowActivation extends Activity {
     private static final String LOG_TAG = "InCallScreenShowActivation";
     private static final boolean DBG =
-            (PhoneApp.DBG_LEVEL >= 1) && (SystemProperties.getInt("ro.debuggable", 0) == 1);
+            (PhoneGlobals.DBG_LEVEL >= 1) && (SystemProperties.getInt("ro.debuggable", 0) == 1);
 
     @Override
     protected void onCreate(Bundle icicle) {
@@ -56,7 +56,7 @@
             Log.d(LOG_TAG, "      - extras = " + extras);
         }
 
-        PhoneApp app = PhoneApp.getInstance();
+        PhoneGlobals app = PhoneGlobals.getInstance();
         Phone phone = app.getPhone();
         if (!TelephonyCapabilities.supportsOtasp(phone)) {
             Log.w(LOG_TAG, "CDMA Provisioning not supported on this device");
@@ -69,7 +69,7 @@
 
             // On voice-capable devices, we perform CDMA provisioning in
             // "interactive" mode by directly launching the InCallScreen.
-            boolean interactiveMode = PhoneApp.sVoiceCapable;
+            boolean interactiveMode = PhoneGlobals.sVoiceCapable;
             Log.d(LOG_TAG, "ACTION_PERFORM_CDMA_PROVISIONING (interactiveMode = "
                   + interactiveMode + ")...");
 
diff --git a/src/com/android/phone/InCallTouchUi.java b/src/com/android/phone/InCallTouchUi.java
index 84176d1..986765e 100644
--- a/src/com/android/phone/InCallTouchUi.java
+++ b/src/com/android/phone/InCallTouchUi.java
@@ -41,6 +41,7 @@
 import android.widget.FrameLayout;
 import android.widget.ImageButton;
 import android.widget.PopupMenu;
+import android.widget.TextView;
 import android.widget.Toast;
 
 import com.android.internal.telephony.Call;
@@ -61,7 +62,7 @@
         implements View.OnClickListener, View.OnLongClickListener, OnTriggerListener,
         PopupMenu.OnMenuItemClickListener, PopupMenu.OnDismissListener {
     private static final String LOG_TAG = "InCallTouchUi";
-    private static final boolean DBG = (PhoneApp.DBG_LEVEL >= 2);
+    private static final boolean DBG = (PhoneGlobals.DBG_LEVEL >= 2);
 
     // Incoming call widget targets
     private static final int ANSWER_CALL_ID = 0;  // drag right
@@ -76,7 +77,7 @@
     private InCallScreen mInCallScreen;
 
     // Phone app instance
-    private PhoneApp mApp;
+    private PhoneGlobals mApp;
 
     // UI containers / elements
     private GlowPadView mIncomingCallWidget;  // UI used for an incoming call
@@ -142,7 +143,7 @@
         if (DBG) log("InCallTouchUi constructor...");
         if (DBG) log("- this = " + this);
         if (DBG) log("- context " + context + ", attrs " + attrs);
-        mApp = PhoneApp.getInstance();
+        mApp = PhoneGlobals.getInstance();
     }
 
     void setInCallScreenInstance(InCallScreen inCallScreen) {
@@ -207,14 +208,20 @@
         // Buttons shown on the "extra button row", only visible in certain (rare) states.
         mExtraButtonRow = (ViewStub) mInCallControls.findViewById(R.id.extraButtonRow);
 
-        // Add a custom OnTouchListener to manually shrink the "hit target".
-        View.OnTouchListener smallerHitTargetTouchListener = new SmallerHitTargetTouchListener();
-        mEndButton.setOnTouchListener(smallerHitTargetTouchListener);
+        // If in PORTRAIT, add a custom OnTouchListener to shrink the "hit target".
+        if (!PhoneUtils.isLandscape(this.getContext())) {
+            mEndButton.setOnTouchListener(new SmallerHitTargetTouchListener());
+        }
+
     }
 
     /**
      * Updates the visibility and/or state of our UI elements, based on
      * the current state of the phone.
+     *
+     * TODO: This function should be relying on a state defined by InCallScreen,
+     * and not generic call states. The incoming call screen handles more states
+     * than Call.State or PhoneConstant.State know about.
      */
     /* package */ void updateState(CallManager cm) {
         if (mInCallScreen == null) {
@@ -263,6 +270,24 @@
                 log("updateState: Too soon after last action; not drawing!");
                 showIncomingCallControls = false;
             }
+
+            // b/6765896
+            // If the glowview triggers two hits of the respond-via-sms gadget in
+            // quick succession, it can cause the incoming call widget to show and hide
+            // twice in a row.  However, the second hide doesn't get triggered because
+            // we are already attemping to hide.  This causes an additional glowview to
+            // stay up above all other screens.
+            // In reality, we shouldn't even be showing incoming-call UI while we are
+            // showing the respond-via-sms popup, so we check for that here.
+            //
+            // TODO: In the future, this entire state machine
+            // should be reworked.  Respond-via-sms was stapled onto the current
+            // design (and so were other states) and should be made a first-class
+            // citizen in a new state machine.
+            if (mInCallScreen.isQuickResponseDialogShowing()) {
+                log("updateState: quickResponse visible. Cancel showing incoming call controls.");
+                showIncomingCallControls = false;
+            }
         } else {
             // Ok, show the regular in-call touch UI (with some exceptions):
             if (okToShowInCallControls()) {
@@ -420,6 +445,7 @@
         }
         return false;
     }
+
     /**
      * Updates the enabledness and "checked" state of the buttons on the
      * "inCallControls" panel, based on the current telephony state.
@@ -523,10 +549,12 @@
             mHoldButton.setEnabled(true);
             mHoldButton.setChecked(inCallControlState.onHold);
             mSwapButton.setVisibility(View.GONE);
+            mHoldSwapSpacer.setVisibility(View.VISIBLE);
         } else if (inCallControlState.canSwap) {
             mSwapButton.setVisibility(View.VISIBLE);
             mSwapButton.setEnabled(true);
             mHoldButton.setVisibility(View.GONE);
+            mHoldSwapSpacer.setVisibility(View.VISIBLE);
         } else {
             // Neither "Hold" nor "Swap" is available.  This can happen for two
             // reasons:
@@ -1057,6 +1085,9 @@
         //
         // If requested above (i.e. if mShowInCallControlsDuringHidingAnimation is set to true),
         // in-call controls will start being shown too.
+        //
+        // TODO: The decision to hide this should be made by the controller
+        // (InCallScreen), and not this view.
         hideIncomingCallWidget();
 
         // Regardless of what action the user did, be sure to clear out
@@ -1072,16 +1103,14 @@
      * Apply an animation to hide the incoming call widget.
      */
     private void hideIncomingCallWidget() {
-        // if (DBG) log("hideIncomingCallWidget()...");
+        if (DBG) log("hideIncomingCallWidget()...");
         if (mIncomingCallWidget.getVisibility() != View.VISIBLE
                 || mIncomingCallWidgetIsFadingOut) {
+            if (DBG) log("Skipping hideIncomingCallWidget action");
             // Widget is already hidden or in the process of being hidden
             return;
         }
 
-        // TODO: remove this once we fixed issue 6603655
-        log("hideIncomingCallWidget()");
-
         // Hide the incoming call screen with a transition
         mIncomingCallWidgetIsFadingOut = true;
         ViewPropertyAnimator animator = mIncomingCallWidget.animate();
@@ -1096,6 +1125,7 @@
                     mInCallControls.setVisibility(View.VISIBLE);
                 }
             }
+
             @Override
             public void onAnimationEnd(Animator animation) {
                 if (DBG) log("IncomingCallWidget's hiding animation ended");
@@ -1106,6 +1136,7 @@
                 mIncomingCallWidgetIsFadingOut = false;
                 mIncomingCallWidgetShouldBeReset = true;
             }
+
             @Override
             public void onAnimationCancel(Animator animation) {
                 mIncomingCallWidget.animate().setListener(null);
@@ -1124,12 +1155,11 @@
      * Shows the incoming call widget and cancels any animation that may be fading it out.
      */
     private void showIncomingCallWidget(Call ringingCall) {
-        // if (DBG) log("showIncomingCallWidget()...");
+        if (DBG) log("showIncomingCallWidget()...");
 
-        // TODO: remove this once we fixed issue 6603655
         // TODO: wouldn't be ok to suppress this whole request if the widget is already VISIBLE
         //       and we don't need to reset it?
-        log("showIncomingCallWidget(). widget visibility: " + mIncomingCallWidget.getVisibility());
+        // log("showIncomingCallWidget(). widget visibility: " + mIncomingCallWidget.getVisibility());
 
         ViewPropertyAnimator animator = mIncomingCallWidget.animate();
         if (animator != null) {
@@ -1179,6 +1209,16 @@
             mIncomingCallWidgetShouldBeReset = false;
         }
 
+        // On an incoming call, if the layout is landscape, then align the "incoming call" text
+        // to the left, because the incomingCallWidget (black background with glowing ring)
+        // is aligned to the right and would cover the "incoming call" text.
+        // Note that callStateLabel is within CallCard, outside of the context of InCallTouchUi
+        if (PhoneUtils.isLandscape(this.getContext())) {
+            TextView callStateLabel = (TextView) mIncomingCallWidget
+                    .getRootView().findViewById(R.id.callStateLabel);
+            if (callStateLabel != null) callStateLabel.setGravity(Gravity.LEFT);
+        }
+
         mIncomingCallWidget.setVisibility(View.VISIBLE);
 
         // Finally, manually trigger a "ping" animation.
diff --git a/src/com/android/phone/InCallUiState.java b/src/com/android/phone/InCallUiState.java
index cfaed99..3b700d7 100644
--- a/src/com/android/phone/InCallUiState.java
+++ b/src/com/android/phone/InCallUiState.java
@@ -393,8 +393,8 @@
      * call. See also {@link InCallScreen} for more detail. There is *no* specific specification
      * about how this variable will be used.
      *
-     * @see PhoneApp#setLatestActiveCallOrigin(String)
-     * @see PhoneApp#createPhoneEndIntentUsingCallOrigin()
+     * @see PhoneGlobals#setLatestActiveCallOrigin(String)
+     * @see PhoneGlobals#createPhoneEndIntentUsingCallOrigin()
      *
      * TODO: we should determine some public behavior for this variable.
      */
diff --git a/src/com/android/phone/ManageConferenceUtils.java b/src/com/android/phone/ManageConferenceUtils.java
index e884798..5821754 100644
--- a/src/com/android/phone/ManageConferenceUtils.java
+++ b/src/com/android/phone/ManageConferenceUtils.java
@@ -41,7 +41,7 @@
 public class ManageConferenceUtils {
     private static final String LOG_TAG = "ManageConferenceUtils";
     private static final boolean DBG =
-            (PhoneApp.DBG_LEVEL >= 1) && (SystemProperties.getInt("ro.debuggable", 0) == 1);
+            (PhoneGlobals.DBG_LEVEL >= 1) && (SystemProperties.getInt("ro.debuggable", 0) == 1);
 
     /**
      * CallerInfoAsyncQuery.OnQueryCompleteListener implementation.
@@ -232,7 +232,7 @@
                     @Override
                     public void onClick(View v) {
                         endConferenceConnection(i, connection);
-                        PhoneApp.getInstance().pokeUserActivity();
+                        PhoneGlobals.getInstance().pokeUserActivity();
                     }
                 };
             endButton.setOnClickListener(endThisConnection);
@@ -242,7 +242,7 @@
                         @Override
                         public void onClick(View v) {
                             separateConferenceConnection(i, connection);
-                            PhoneApp.getInstance().pokeUserActivity();
+                            PhoneGlobals.getInstance().pokeUserActivity();
                         }
                     };
                 separateButton.setOnClickListener(separateThisConnection);
diff --git a/src/com/android/phone/MobileNetworkSettings.java b/src/com/android/phone/MobileNetworkSettings.java
index 2948216..a81d7c2 100644
--- a/src/com/android/phone/MobileNetworkSettings.java
+++ b/src/com/android/phone/MobileNetworkSettings.java
@@ -144,8 +144,8 @@
             return true;
         } else if (preference == mButtonPreferredNetworkMode) {
             //displays the value taken from the Settings.System
-            int settingsNetworkMode = android.provider.Settings.Secure.getInt(mPhone.getContext().
-                    getContentResolver(), android.provider.Settings.Secure.PREFERRED_NETWORK_MODE,
+            int settingsNetworkMode = android.provider.Settings.Global.getInt(mPhone.getContext().
+                    getContentResolver(), android.provider.Settings.Global.PREFERRED_NETWORK_MODE,
                     preferredNetworkMode);
             mButtonPreferredNetworkMode.setValue(Integer.toString(settingsNetworkMode));
             return true;
@@ -176,8 +176,8 @@
             cm.setMobileDataEnabled(mButtonDataEnabled.isChecked());
             return true;
         } else if (preference == mLteDataServicePref) {
-            String tmpl = android.provider.Settings.Secure.getString(getContentResolver(),
-                        android.provider.Settings.Secure.SETUP_PREPAID_DATA_SERVICE_URL);
+            String tmpl = android.provider.Settings.Global.getString(getContentResolver(),
+                        android.provider.Settings.Global.SETUP_PREPAID_DATA_SERVICE_URL);
             if (!TextUtils.isEmpty(tmpl)) {
                 TelephonyManager tm = (TelephonyManager) getSystemService(
                         Context.TELEPHONY_SERVICE);
@@ -209,7 +209,7 @@
 
         addPreferencesFromResource(R.xml.network_setting);
 
-        mPhone = PhoneApp.getPhone();
+        mPhone = PhoneGlobals.getPhone();
         mHandler = new MyHandler();
 
         //get UI object references
@@ -229,8 +229,8 @@
             mButtonPreferredNetworkMode.setOnPreferenceChangeListener(this);
 
             //Get the networkMode from Settings.System and displays it
-            int settingsNetworkMode = android.provider.Settings.Secure.getInt(mPhone.getContext().
-                    getContentResolver(),android.provider.Settings.Secure.PREFERRED_NETWORK_MODE,
+            int settingsNetworkMode = android.provider.Settings.Global.getInt(mPhone.getContext().
+                    getContentResolver(),android.provider.Settings.Global.PREFERRED_NETWORK_MODE,
                     preferredNetworkMode);
             mButtonPreferredNetworkMode.setValue(Integer.toString(settingsNetworkMode));
             mCdmaOptions = new CdmaOptions(this, prefSet, mPhone);
@@ -248,9 +248,9 @@
                             R.array.preferred_network_mode_choices_lte);
                     mButtonPreferredNetworkMode.setEntryValues(
                             R.array.preferred_network_mode_values_lte);
-                    int settingsNetworkMode = android.provider.Settings.Secure.getInt(
+                    int settingsNetworkMode = android.provider.Settings.Global.getInt(
                             mPhone.getContext().getContentResolver(),
-                            android.provider.Settings.Secure.PREFERRED_NETWORK_MODE,
+                            android.provider.Settings.Global.PREFERRED_NETWORK_MODE,
                             preferredNetworkMode);
                     mButtonPreferredNetworkMode.setValue(
                             Integer.toString(settingsNetworkMode));
@@ -264,8 +264,8 @@
         }
 
         final boolean missingDataServiceUrl = TextUtils.isEmpty(
-                android.provider.Settings.Secure.getString(getContentResolver(),
-                        android.provider.Settings.Secure.SETUP_PREPAID_DATA_SERVICE_URL));
+                android.provider.Settings.Global.getString(getContentResolver(),
+                        android.provider.Settings.Global.SETUP_PREPAID_DATA_SERVICE_URL));
         if (!isLteOnCdma || missingDataServiceUrl) {
             prefSet.removePreference(mLteDataServicePref);
         } else {
@@ -327,9 +327,9 @@
             mButtonPreferredNetworkMode.setValue((String) objValue);
             int buttonNetworkMode;
             buttonNetworkMode = Integer.valueOf((String) objValue).intValue();
-            int settingsNetworkMode = android.provider.Settings.Secure.getInt(
+            int settingsNetworkMode = android.provider.Settings.Global.getInt(
                     mPhone.getContext().getContentResolver(),
-                    android.provider.Settings.Secure.PREFERRED_NETWORK_MODE, preferredNetworkMode);
+                    android.provider.Settings.Global.PREFERRED_NETWORK_MODE, preferredNetworkMode);
             if (buttonNetworkMode != settingsNetworkMode) {
                 int modemNetworkMode;
                 switch(buttonNetworkMode) {
@@ -371,8 +371,8 @@
 
                 UpdatePreferredNetworkModeSummary(buttonNetworkMode);
 
-                android.provider.Settings.Secure.putInt(mPhone.getContext().getContentResolver(),
-                        android.provider.Settings.Secure.PREFERRED_NETWORK_MODE,
+                android.provider.Settings.Global.putInt(mPhone.getContext().getContentResolver(),
+                        android.provider.Settings.Global.PREFERRED_NETWORK_MODE,
                         buttonNetworkMode );
                 //Set the modem network mode
                 mPhone.setPreferredNetworkType(modemNetworkMode, mHandler
@@ -413,9 +413,9 @@
                             modemNetworkMode);
                 }
 
-                int settingsNetworkMode = android.provider.Settings.Secure.getInt(
+                int settingsNetworkMode = android.provider.Settings.Global.getInt(
                         mPhone.getContext().getContentResolver(),
-                        android.provider.Settings.Secure.PREFERRED_NETWORK_MODE,
+                        android.provider.Settings.Global.PREFERRED_NETWORK_MODE,
                         preferredNetworkMode);
 
                 if (DBG) {
@@ -451,9 +451,9 @@
                         }
 
                         //changes the Settings.System accordingly to modemNetworkMode
-                        android.provider.Settings.Secure.putInt(
+                        android.provider.Settings.Global.putInt(
                                 mPhone.getContext().getContentResolver(),
-                                android.provider.Settings.Secure.PREFERRED_NETWORK_MODE,
+                                android.provider.Settings.Global.PREFERRED_NETWORK_MODE,
                                 settingsNetworkMode );
                     }
 
@@ -476,8 +476,8 @@
             if (ar.exception == null) {
                 int networkMode = Integer.valueOf(
                         mButtonPreferredNetworkMode.getValue()).intValue();
-                android.provider.Settings.Secure.putInt(mPhone.getContext().getContentResolver(),
-                        android.provider.Settings.Secure.PREFERRED_NETWORK_MODE,
+                android.provider.Settings.Global.putInt(mPhone.getContext().getContentResolver(),
+                        android.provider.Settings.Global.PREFERRED_NETWORK_MODE,
                         networkMode );
             } else {
                 mPhone.getPreferredNetworkType(obtainMessage(MESSAGE_GET_PREFERRED_NETWORK_TYPE));
@@ -488,8 +488,8 @@
             //set the mButtonPreferredNetworkMode
             mButtonPreferredNetworkMode.setValue(Integer.toString(preferredNetworkMode));
             //set the Settings.System
-            android.provider.Settings.Secure.putInt(mPhone.getContext().getContentResolver(),
-                        android.provider.Settings.Secure.PREFERRED_NETWORK_MODE,
+            android.provider.Settings.Global.putInt(mPhone.getContext().getContentResolver(),
+                        android.provider.Settings.Global.PREFERRED_NETWORK_MODE,
                         preferredNetworkMode );
             //Set the Modem
             mPhone.setPreferredNetworkType(preferredNetworkMode,
diff --git a/src/com/android/phone/NetworkSetting.java b/src/com/android/phone/NetworkSetting.java
index 87bd05a..a11ebab 100644
--- a/src/com/android/phone/NetworkSetting.java
+++ b/src/com/android/phone/NetworkSetting.java
@@ -219,7 +219,7 @@
 
         addPreferencesFromResource(R.xml.carrier_select);
 
-        mPhone = PhoneApp.getPhone();
+        mPhone = PhoneGlobals.getPhone();
 
         mNetworkList = (PreferenceGroup) getPreferenceScreen().findPreference(LIST_NETWORKS_KEY);
         mNetworkMap = new HashMap<Preference, OperatorInfo>();
@@ -322,7 +322,7 @@
     private void displayNetworkQueryFailed(int error) {
         String status = getResources().getString(R.string.network_query_error);
 
-        final PhoneApp app = PhoneApp.getInstance();
+        final PhoneGlobals app = PhoneGlobals.getInstance();
         app.notificationMgr.postTransientNotification(
                 NotificationMgr.NETWORK_SELECTION_NOTIFICATION, status);
     }
@@ -339,7 +339,7 @@
             status = getResources().getString(R.string.connect_later);
         }
 
-        final PhoneApp app = PhoneApp.getInstance();
+        final PhoneGlobals app = PhoneGlobals.getInstance();
         app.notificationMgr.postTransientNotification(
                 NotificationMgr.NETWORK_SELECTION_NOTIFICATION, status);
     }
@@ -347,7 +347,7 @@
     private void displayNetworkSelectionSucceeded() {
         String status = getResources().getString(R.string.registration_done);
 
-        final PhoneApp app = PhoneApp.getInstance();
+        final PhoneGlobals app = PhoneGlobals.getInstance();
         app.notificationMgr.postTransientNotification(
                 NotificationMgr.NETWORK_SELECTION_NOTIFICATION, status);
 
diff --git a/src/com/android/phone/NotificationMgr.java b/src/com/android/phone/NotificationMgr.java
index 530389c..044418c 100644
--- a/src/com/android/phone/NotificationMgr.java
+++ b/src/com/android/phone/NotificationMgr.java
@@ -65,12 +65,12 @@
  * framework's NotificationManager, and is used to display status bar
  * icons and control other status bar-related behavior.
  *
- * @see PhoneApp.notificationMgr
+ * @see PhoneGlobals.notificationMgr
  */
 public class NotificationMgr implements CallerInfoAsyncQuery.OnQueryCompleteListener{
     private static final String LOG_TAG = "NotificationMgr";
     private static final boolean DBG =
-            (PhoneApp.DBG_LEVEL >= 1) && (SystemProperties.getInt("ro.debuggable", 0) == 1);
+            (PhoneGlobals.DBG_LEVEL >= 1) && (SystemProperties.getInt("ro.debuggable", 0) == 1);
     // Do not check in with VDBG = true, since that may write PII to the system log.
     private static final boolean VDBG = false;
 
@@ -95,7 +95,7 @@
     /** The singleton NotificationMgr instance. */
     private static NotificationMgr sInstance;
 
-    private PhoneApp mApp;
+    private PhoneGlobals mApp;
     private Phone mPhone;
     private CallManager mCM;
 
@@ -133,7 +133,7 @@
      * Private constructor (this is a singleton).
      * @see init()
      */
-    private NotificationMgr(PhoneApp app) {
+    private NotificationMgr(PhoneGlobals app) {
         mApp = app;
         mContext = app;
         mNotificationManager =
@@ -155,7 +155,7 @@
      * PhoneApp's public "notificationMgr" field, which is why there's no
      * getInstance() method here.
      */
-    /* package */ static NotificationMgr init(PhoneApp app) {
+    /* package */ static NotificationMgr init(PhoneGlobals app) {
         synchronized (NotificationMgr.class) {
             if (sInstance == null) {
                 sInstance = new NotificationMgr(app);
@@ -484,12 +484,12 @@
             String name, String number, String type, Drawable photo, Bitmap photoIcon, long date) {
 
         // When the user clicks this notification, we go to the call log.
-        final Intent callLogIntent = PhoneApp.createCallLogIntent();
+        final Intent callLogIntent = PhoneGlobals.createCallLogIntent();
 
         // Never display the missed call notification on non-voice-capable
         // devices, even if the device does somehow manage to get an
         // incoming call.
-        if (!PhoneApp.sVoiceCapable) {
+        if (!PhoneGlobals.sVoiceCapable) {
             if (DBG) log("notifyMissedCall: non-voice-capable device, not posting notification");
             return;
         }
@@ -553,11 +553,11 @@
 
             builder.addAction(R.drawable.stat_sys_phone_call,
                     mContext.getString(R.string.notification_missedCall_call_back),
-                    PhoneApp.getCallBackPendingIntent(mContext, number));
+                    PhoneGlobals.getCallBackPendingIntent(mContext, number));
 
             builder.addAction(R.drawable.ic_text_holo_dark,
                     mContext.getString(R.string.notification_missedCall_message),
-                    PhoneApp.getSendSmsFromNotificationPendingIntent(mContext, number));
+                    PhoneGlobals.getSendSmsFromNotificationPendingIntent(mContext, number));
 
             if (photoIcon != null) {
                 builder.setLargeIcon(photoIcon);
@@ -777,7 +777,7 @@
         // Never display the "ongoing call" notification on
         // non-voice-capable devices, even if the phone is actually
         // offhook (like during a non-interactive OTASP call.)
-        if (!PhoneApp.sVoiceCapable) {
+        if (!PhoneGlobals.sVoiceCapable) {
             if (DBG) log("- non-voice-capable device; suppressing notification.");
             return;
         }
@@ -892,7 +892,7 @@
         // call (see the "fullScreenIntent" field below).
         PendingIntent inCallPendingIntent =
                 PendingIntent.getActivity(mContext, 0,
-                                          PhoneApp.createInCallIntent(), 0);
+                                          PhoneGlobals.createInCallIntent(), 0);
         builder.setContentIntent(inCallPendingIntent);
 
         // Update icon on the left of the notification.
@@ -989,7 +989,16 @@
                 // and translate that into the elapsedRealtime() timebase.
                 long callDurationMsec = currentConn.getDurationMillis();
                 builder.setWhen(System.currentTimeMillis() - callDurationMsec);
-                builder.setContentText(mContext.getString(R.string.notification_ongoing_call));
+
+                int contextTextId = R.string.notification_ongoing_call;
+
+                Call call = mCM.getActiveFgCall();
+                if (TelephonyCapabilities.canDistinguishDialingAndConnected(
+                        call.getPhone().getPhoneType()) && call.isDialingOrAlerting()) {
+                  contextTextId = R.string.notification_dialing;
+                }
+
+                builder.setContentText(mContext.getString(contextTextId));
             }
         } else if (DBG) {
             Log.w(LOG_TAG, "updateInCallNotification: null connection, can't set exp view line 1.");
@@ -1093,7 +1102,7 @@
             // TODO: use better asset.
             builder.addAction(R.drawable.stat_sys_phone_call_end,
                     mContext.getText(R.string.notification_action_end_call),
-                    PhoneApp.createHangUpOngoingCallPendingIntent(mContext));
+                    PhoneGlobals.createHangUpOngoingCallPendingIntent(mContext));
         }
 
         Notification notification = builder.getNotification();
diff --git a/src/com/android/phone/OtaStartupReceiver.java b/src/com/android/phone/OtaStartupReceiver.java
index 180041f..594b63a 100644
--- a/src/com/android/phone/OtaStartupReceiver.java
+++ b/src/com/android/phone/OtaStartupReceiver.java
@@ -86,7 +86,7 @@
                     // it's finally OK to start OTA provisioning
                     if (state.getState() == ServiceState.STATE_IN_SERVICE) {
                         if (DBG) Log.d(TAG, "call OtaUtils.maybeDoOtaCall after network is available");
-                        Phone phone = PhoneApp.getPhone();
+                        Phone phone = PhoneGlobals.getPhone();
                         phone.unregisterForServiceStateChanged(this);
                         OtaUtils.maybeDoOtaCall(mContext, mHandler, MIN_READY);
                     }
@@ -105,7 +105,13 @@
                     "  mOtaspMode=" + mOtaspMode);
         }
 
-        if (!TelephonyCapabilities.supportsOtasp(PhoneApp.getPhone())) {
+        PhoneGlobals globals = PhoneGlobals.getInstanceIfPrimary();
+        if (globals == null) {
+            if (DBG) Log.d(TAG, "Not primary user, nothing to do.");
+            return;
+        }
+
+        if (!TelephonyCapabilities.supportsOtasp(PhoneGlobals.getPhone())) {
             if (DBG) Log.d(TAG, "OTASP not supported, nothing to do.");
             return;
         }
@@ -126,8 +132,8 @@
         }
 
         // Delay OTA provisioning if network is not available yet
-        PhoneApp app = PhoneApp.getInstance();
-        Phone phone = PhoneApp.getPhone();
+        PhoneGlobals app = PhoneGlobals.getInstance();
+        Phone phone = PhoneGlobals.getPhone();
         if (app.mCM.getServiceState() != ServiceState.STATE_IN_SERVICE) {
             if (DBG) Log.w(TAG, "Network is not ready. Registering to receive notification.");
             phone.registerForServiceStateChanged(mHandler, SERVICE_STATE_CHANGED, null);
@@ -158,8 +164,8 @@
         Intent intent = new Intent("android.intent.action.DEVICE_INITIALIZATION_WIZARD");
         ResolveInfo resolveInfo = context.getPackageManager().resolveActivity(intent,
                 PackageManager.MATCH_DEFAULT_ONLY);
-        boolean provisioned = Settings.Secure.getInt(context.getContentResolver(),
-                Settings.Secure.DEVICE_PROVISIONED, 0) != 0;
+        boolean provisioned = Settings.Global.getInt(context.getContentResolver(),
+                Settings.Global.DEVICE_PROVISIONED, 0) != 0;
         String mode = SystemProperties.get("ro.setupwizard.mode", "REQUIRED");
         boolean runningSetupWizard = "REQUIRED".equals(mode) || "OPTIONAL".equals(mode);
         if (DBG) {
diff --git a/src/com/android/phone/OtaUtils.java b/src/com/android/phone/OtaUtils.java
index 572c6ac..495df27 100644
--- a/src/com/android/phone/OtaUtils.java
+++ b/src/com/android/phone/OtaUtils.java
@@ -27,6 +27,7 @@
 import android.app.AlertDialog;
 import android.app.PendingIntent;
 import android.app.PendingIntent.CanceledException;
+import android.content.ActivityNotFoundException;
 import android.content.Context;
 import android.content.DialogInterface;
 import android.content.Intent;
@@ -35,6 +36,7 @@
 import android.os.Handler;
 import android.os.SystemClock;
 import android.os.SystemProperties;
+import android.os.UserHandle;
 import android.telephony.TelephonyManager;
 import android.util.Log;
 import android.view.KeyEvent;
@@ -141,7 +143,7 @@
 
     private InCallScreen mInCallScreen;
     private Context mContext;
-    private PhoneApp mApplication;
+    private PhoneGlobals mApplication;
     private OtaWidgetData mOtaWidgetData;
     private ViewGroup mInCallTouchUi;  // UI controls for regular calls
     private CallCard mCallCard;
@@ -214,7 +216,7 @@
      */
     public OtaUtils(Context context, boolean interactive) {
         if (DBG) log("OtaUtils constructor...");
-        mApplication = PhoneApp.getInstance();
+        mApplication = PhoneGlobals.getInstance();
         mContext = context;
         mInteractive = interactive;
     }
@@ -282,7 +284,7 @@
      * @return true if we were able to launch Ota activity or it's not required; false otherwise
      */
     public static boolean maybeDoOtaCall(Context context, Handler handler, int request) {
-        PhoneApp app = PhoneApp.getInstance();
+        PhoneGlobals app = PhoneGlobals.getInstance();
         Phone phone = app.phone;
 
         if (ActivityManager.isRunningInTestHarness()) {
@@ -324,7 +326,7 @@
 
         // Run the OTASP call in "interactive" mode only if
         // this is a non-LTE "voice capable" device.
-        if (PhoneApp.sVoiceCapable && getLteOnCdmaMode(context) == PhoneConstants.LTE_ON_CDMA_FALSE) {
+        if (PhoneGlobals.sVoiceCapable && getLteOnCdmaMode(context) == PhoneConstants.LTE_ON_CDMA_FALSE) {
             if (phoneNeedsActivation
                     && (otaShowActivationScreen == OTA_SHOW_ACTIVATION_SCREEN_ON)) {
                 app.cdmaOtaProvisionData.isOtaCallIntentProcessed = false;
@@ -343,7 +345,12 @@
                 Intent newIntent = new Intent(ACTION_PERFORM_VOICELESS_CDMA_PROVISIONING);
                 newIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                 newIntent.putExtra(EXTRA_VOICELESS_PROVISIONING_OFFER_DONTSHOW, true);
-                context.startActivity(newIntent);
+                try {
+                    context.startActivity(newIntent);
+                } catch (ActivityNotFoundException e) {
+                    loge("No activity Handling PERFORM_VOICELESS_CDMA_PROVISIONING!");
+                    return false;
+                }
                 if (DBG) log("maybeDoOtaCall: non-interactive; activation intent sent.");
             } else {
                 if (DBG) log("maybeDoOtaCall: non-interactive, no need for OTASP.");
@@ -361,7 +368,7 @@
      */
     public static void startInteractiveOtasp(Context context) {
         if (DBG) log("startInteractiveOtasp()...");
-        PhoneApp app = PhoneApp.getInstance();
+        PhoneGlobals app = PhoneGlobals.getInstance();
 
         // There are two ways to start OTASP on voice-capable devices:
         //
@@ -426,7 +433,7 @@
      */
     public static int startNonInteractiveOtasp(Context context) {
         if (DBG) log("startNonInteractiveOtasp()...");
-        PhoneApp app = PhoneApp.getInstance();
+        PhoneGlobals app = PhoneGlobals.getInstance();
 
         if (app.otaUtils != null) {
             // An OtaUtils instance already exists, presumably from a previous OTASP call.
@@ -442,7 +449,7 @@
         // TODO(InCallScreen redesign): This should probably go through
         // the CallController, rather than directly calling
         // PhoneUtils.placeCall().
-        Phone phone = PhoneApp.getPhone();
+        Phone phone = PhoneGlobals.getPhone();
         String number = OTASP_NUMBER_NON_INTERACTIVE;
         Log.i(LOG_TAG, "startNonInteractiveOtasp: placing call to '" + number + "'...");
         int callStatus = PhoneUtils.placeCall(context,
@@ -485,7 +492,7 @@
      */
     public static boolean isOtaspCallIntent(Intent intent) {
         if (DBG) log("isOtaspCallIntent(" + intent + ")...");
-        PhoneApp app = PhoneApp.getInstance();
+        PhoneGlobals app = PhoneGlobals.getInstance();
         Phone phone = app.mCM.getDefaultPhone();
 
         if (intent == null) {
@@ -541,7 +548,7 @@
      */
     public static void setupOtaspCall(Intent intent) {
         if (DBG) log("setupOtaspCall(): preparing for OTASP call to " + intent);
-        PhoneApp app = PhoneApp.getInstance();
+        PhoneGlobals app = PhoneGlobals.getInstance();
 
         if (app.otaUtils != null) {
             // An OtaUtils instance already exists, presumably from a prior OTASP call.
@@ -707,7 +714,7 @@
         Intent intent = new Intent(Intent.ACTION_MAIN);
         intent.addCategory (Intent.CATEGORY_HOME);
         intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-        mContext.startActivity(intent);
+        mContext.startActivityAsUser(intent, UserHandle.CURRENT);
         return;
     }
 
@@ -1631,4 +1638,8 @@
     private static void log(String msg) {
         Log.d(LOG_TAG, msg);
     }
+
+    private static void loge(String msg) {
+        Log.e(LOG_TAG, msg);
+    }
 }
diff --git a/src/com/android/phone/OutgoingCallBroadcaster.java b/src/com/android/phone/OutgoingCallBroadcaster.java
index df14ece..dabffa2 100644
--- a/src/com/android/phone/OutgoingCallBroadcaster.java
+++ b/src/com/android/phone/OutgoingCallBroadcaster.java
@@ -29,6 +29,7 @@
 import android.os.Handler;
 import android.os.Message;
 import android.os.SystemProperties;
+import android.os.UserHandle;
 import android.telephony.PhoneNumberUtils;
 import android.text.TextUtils;
 import android.util.Log;
@@ -60,7 +61,7 @@
     private static final String PERMISSION = android.Manifest.permission.PROCESS_OUTGOING_CALLS;
     private static final String TAG = "OutgoingCallBroadcaster";
     private static final boolean DBG =
-            (PhoneApp.DBG_LEVEL >= 1) && (SystemProperties.getInt("ro.debuggable", 0) == 1);
+            (PhoneGlobals.DBG_LEVEL >= 1) && (SystemProperties.getInt("ro.debuggable", 0) == 1);
     // Do not check in with VDBG = true, since that may write PII to the system log.
     private static final boolean VDBG = false;
 
@@ -145,7 +146,7 @@
             number = getResultData();
             if (VDBG) Log.v(TAG, "- got number from resultData: '" + number + "'");
 
-            final PhoneApp app = PhoneApp.getInstance();
+            final PhoneGlobals app = PhoneGlobals.getInstance();
 
             // OTASP-specific checks.
             // TODO: This should probably all happen in
@@ -390,7 +391,7 @@
         final Configuration configuration = getResources().getConfiguration();
 
         // Outgoing phone calls are only allowed on "voice-capable" devices.
-        if (!PhoneApp.sVoiceCapable) {
+        if (!PhoneGlobals.sVoiceCapable) {
             Log.i(TAG, "This device is detected as non-voice-capable device.");
             handleNonVoiceCapable(intent);
             return;
@@ -521,7 +522,7 @@
         // Also, this ensures the device stays awake while doing the following
         // broadcast; technically we should be holding a wake lock here
         // as well.
-        PhoneApp.getInstance().wakeUpScreen();
+        PhoneGlobals.getInstance().wakeUpScreen();
 
         // If number is null, we're probably trying to call a non-existent voicemail number,
         // send an empty flash or something else is fishy.  Whatever the problem, there's no
@@ -529,7 +530,7 @@
         if (TextUtils.isEmpty(number)) {
             if (intent.getBooleanExtra(EXTRA_SEND_EMPTY_FLASH, false)) {
                 Log.i(TAG, "onCreate: SEND_EMPTY_FLASH...");
-                PhoneUtils.sendEmptyFlash(PhoneApp.getPhone());
+                PhoneUtils.sendEmptyFlash(PhoneGlobals.getPhone());
                 finish();
                 return;
             } else {
@@ -547,7 +548,7 @@
 
             // Initiate the outgoing call, and simultaneously launch the
             // InCallScreen to display the in-call UI:
-            PhoneApp.getInstance().callController.placeCall(intent);
+            PhoneGlobals.getInstance().callController.placeCall(intent);
 
             // Note we do *not* "return" here, but instead continue and
             // send the ACTION_NEW_OUTGOING_CALL broadcast like for any
@@ -559,13 +560,13 @@
 
         // Remember the call origin so that users will be able to see an appropriate screen
         // after the phone call. This should affect both phone calls and SIP calls.
-        final String callOrigin = intent.getStringExtra(PhoneApp.EXTRA_CALL_ORIGIN);
+        final String callOrigin = intent.getStringExtra(PhoneGlobals.EXTRA_CALL_ORIGIN);
         if (callOrigin != null) {
             if (DBG) Log.v(TAG, " - Call origin is passed (" + callOrigin + ")");
-            PhoneApp.getInstance().setLatestActiveCallOrigin(callOrigin);
+            PhoneGlobals.getInstance().setLatestActiveCallOrigin(callOrigin);
         } else {
             if (DBG) Log.v(TAG, " - Call origin is not passed. Reset current one.");
-            PhoneApp.getInstance().resetLatestActiveCallOrigin();
+            PhoneGlobals.getInstance().resetLatestActiveCallOrigin();
         }
 
         // For now, SIP calls will be processed directly without a
@@ -609,7 +610,8 @@
         // timeout.
         mHandler.sendEmptyMessageDelayed(EVENT_OUTGOING_CALL_TIMEOUT,
                 OUTGOING_CALL_TIMEOUT_THRESHOLD);
-        sendOrderedBroadcast(broadcastIntent, PERMISSION, new OutgoingCallReceiver(),
+        sendOrderedBroadcastAsUser(broadcastIntent, UserHandle.OWNER,
+                PERMISSION, new OutgoingCallReceiver(),
                 null,  // scheduler
                 Activity.RESULT_OK,  // initialCode
                 number,  // initialData: initial value for the result data
diff --git a/src/com/android/phone/PhoneApp.java b/src/com/android/phone/PhoneApp.java
index 10099f8..e3d3fa9 100644
--- a/src/com/android/phone/PhoneApp.java
+++ b/src/com/android/phone/PhoneApp.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2006 The Android Open Source Project
+ * Copyright (C) 2012 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -16,1993 +16,34 @@
 
 package com.android.phone;
 
-import android.app.Activity;
 import android.app.Application;
-import android.app.KeyguardManager;
-import android.app.PendingIntent;
-import android.app.ProgressDialog;
-import android.bluetooth.BluetoothAdapter;
-import android.bluetooth.BluetoothHeadset;
-import android.bluetooth.BluetoothProfile;
-import android.content.ActivityNotFoundException;
-import android.content.BroadcastReceiver;
-import android.content.ComponentName;
-import android.content.ContentResolver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
 import android.content.res.Configuration;
-import android.media.AudioManager;
-import android.net.Uri;
-import android.os.AsyncResult;
-import android.os.Binder;
-import android.os.Handler;
-import android.os.IBinder;
-import android.os.IPowerManager;
-import android.os.LocalPowerManager;
-import android.os.Message;
-import android.os.PowerManager;
-import android.os.RemoteException;
-import android.os.ServiceManager;
-import android.os.SystemClock;
-import android.os.SystemProperties;
-import android.os.UpdateLock;
-import android.preference.PreferenceManager;
-import android.provider.Settings.System;
-import android.telephony.ServiceState;
-import android.text.TextUtils;
-import android.util.Log;
-import android.view.KeyEvent;
-
-import com.android.internal.telephony.Call;
-import com.android.internal.telephony.CallManager;
-import com.android.internal.telephony.IccCard;
-import com.android.internal.telephony.IccCardConstants;
-import com.android.internal.telephony.MmiCode;
-import com.android.internal.telephony.Phone;
-import com.android.internal.telephony.PhoneConstants;
-import com.android.internal.telephony.PhoneFactory;
-import com.android.internal.telephony.TelephonyCapabilities;
-import com.android.internal.telephony.TelephonyIntents;
-import com.android.internal.telephony.cdma.TtyIntent;
-import com.android.phone.OtaUtils.CdmaOtaScreenState;
-import com.android.server.sip.SipService;
+import android.os.UserHandle;
 
 /**
  * Top-level Application class for the Phone app.
  */
-public class PhoneApp extends Application implements AccelerometerListener.OrientationListener {
-    /* package */ static final String LOG_TAG = "PhoneApp";
-
-    /**
-     * Phone app-wide debug level:
-     *   0 - no debug logging
-     *   1 - normal debug logging if ro.debuggable is set (which is true in
-     *       "eng" and "userdebug" builds but not "user" builds)
-     *   2 - ultra-verbose debug logging
-     *
-     * Most individual classes in the phone app have a local DBG constant,
-     * typically set to
-     *   (PhoneApp.DBG_LEVEL >= 1) && (SystemProperties.getInt("ro.debuggable", 0) == 1)
-     * or else
-     *   (PhoneApp.DBG_LEVEL >= 2)
-     * depending on the desired verbosity.
-     *
-     * ***** DO NOT SUBMIT WITH DBG_LEVEL > 0 *************
-     */
-    /* package */ static final int DBG_LEVEL = 0;
-
-    private static final boolean DBG =
-            (PhoneApp.DBG_LEVEL >= 1) && (SystemProperties.getInt("ro.debuggable", 0) == 1);
-    private static final boolean VDBG = (PhoneApp.DBG_LEVEL >= 2);
-
-    // Message codes; see mHandler below.
-    private static final int EVENT_SIM_NETWORK_LOCKED = 3;
-    private static final int EVENT_WIRED_HEADSET_PLUG = 7;
-    private static final int EVENT_SIM_STATE_CHANGED = 8;
-    private static final int EVENT_UPDATE_INCALL_NOTIFICATION = 9;
-    private static final int EVENT_DATA_ROAMING_DISCONNECTED = 10;
-    private static final int EVENT_DATA_ROAMING_OK = 11;
-    private static final int EVENT_UNSOL_CDMA_INFO_RECORD = 12;
-    private static final int EVENT_DOCK_STATE_CHANGED = 13;
-    private static final int EVENT_TTY_PREFERRED_MODE_CHANGED = 14;
-    private static final int EVENT_TTY_MODE_GET = 15;
-    private static final int EVENT_TTY_MODE_SET = 16;
-    private static final int EVENT_START_SIP_SERVICE = 17;
-
-    // The MMI codes are also used by the InCallScreen.
-    public static final int MMI_INITIATE = 51;
-    public static final int MMI_COMPLETE = 52;
-    public static final int MMI_CANCEL = 53;
-    // Don't use message codes larger than 99 here; those are reserved for
-    // the individual Activities of the Phone UI.
-
-    /**
-     * Allowable values for the poke lock code (timeout between a user activity and the
-     * going to sleep), please refer to {@link com.android.server.PowerManagerService}
-     * for additional reference.
-     *   SHORT uses the short delay for the timeout (SHORT_KEYLIGHT_DELAY, 6 sec)
-     *   MEDIUM uses the medium delay for the timeout (MEDIUM_KEYLIGHT_DELAY, 15 sec)
-     *   DEFAULT is the system-wide default delay for the timeout (1 min)
-     */
-    public enum ScreenTimeoutDuration {
-        SHORT,
-        MEDIUM,
-        DEFAULT
-    }
-
-    /**
-     * Allowable values for the wake lock code.
-     *   SLEEP means the device can be put to sleep.
-     *   PARTIAL means wake the processor, but we display can be kept off.
-     *   FULL means wake both the processor and the display.
-     */
-    public enum WakeState {
-        SLEEP,
-        PARTIAL,
-        FULL
-    }
-
-    /**
-     * Intent Action used for hanging up the current call from Notification bar. This will
-     * choose first ringing call, first active call, or first background call (typically in
-     * HOLDING state).
-     */
-    public static final String ACTION_HANG_UP_ONGOING_CALL =
-            "com.android.phone.ACTION_HANG_UP_ONGOING_CALL";
-
-    /**
-     * Intent Action used for making a phone call from Notification bar.
-     * This is for missed call notifications.
-     */
-    public static final String ACTION_CALL_BACK_FROM_NOTIFICATION =
-            "com.android.phone.ACTION_CALL_BACK_FROM_NOTIFICATION";
-
-    /**
-     * Intent Action used for sending a SMS from notification bar.
-     * This is for missed call notifications.
-     */
-    public static final String ACTION_SEND_SMS_FROM_NOTIFICATION =
-            "com.android.phone.ACTION_SEND_SMS_FROM_NOTIFICATION";
-
-    private static PhoneApp sMe;
-
-    // A few important fields we expose to the rest of the package
-    // directly (rather than thru set/get methods) for efficiency.
-    Phone phone;
-    CallController callController;
-    InCallUiState inCallUiState;
-    CallerInfoCache callerInfoCache;
-    CallNotifier notifier;
-    NotificationMgr notificationMgr;
-    Ringer ringer;
-    BluetoothHandsfree mBtHandsfree;
-    PhoneInterfaceManager phoneMgr;
-    CallManager mCM;
-    int mBluetoothHeadsetState = BluetoothProfile.STATE_DISCONNECTED;
-    int mBluetoothHeadsetAudioState = BluetoothHeadset.STATE_AUDIO_DISCONNECTED;
-    boolean mShowBluetoothIndication = false;
-    static int mDockState = Intent.EXTRA_DOCK_STATE_UNDOCKED;
-    static boolean sVoiceCapable = true;
-
-    // Internal PhoneApp Call state tracker
-    CdmaPhoneCallState cdmaPhoneCallState;
-
-    // The InCallScreen instance (or null if the InCallScreen hasn't been
-    // created yet.)
-    private InCallScreen mInCallScreen;
-
-    // The currently-active PUK entry activity and progress dialog.
-    // Normally, these are the Emergency Dialer and the subsequent
-    // progress dialog.  null if there is are no such objects in
-    // the foreground.
-    private Activity mPUKEntryActivity;
-    private ProgressDialog mPUKEntryProgressDialog;
-
-    private boolean mIsSimPinEnabled;
-    private String mCachedSimPin;
-
-    // True if a wired headset is currently plugged in, based on the state
-    // from the latest Intent.ACTION_HEADSET_PLUG broadcast we received in
-    // mReceiver.onReceive().
-    private boolean mIsHeadsetPlugged;
-
-    // True if the keyboard is currently *not* hidden
-    // Gets updated whenever there is a Configuration change
-    private boolean mIsHardKeyboardOpen;
-
-    // True if we are beginning a call, but the phone state has not changed yet
-    private boolean mBeginningCall;
-
-    // Last phone state seen by updatePhoneState()
-    private PhoneConstants.State mLastPhoneState = PhoneConstants.State.IDLE;
-
-    private WakeState mWakeState = WakeState.SLEEP;
-
-    /**
-     * Timeout setting used by PokeLock.
-     *
-     * This variable won't be effective when proximity sensor is available in the device.
-     *
-     * @see ScreenTimeoutDuration
-     */
-    private ScreenTimeoutDuration mScreenTimeoutDuration = ScreenTimeoutDuration.DEFAULT;
-    /**
-     * Used to set/unset {@link LocalPowerManager#POKE_LOCK_IGNORE_TOUCH_EVENTS} toward PokeLock.
-     *
-     * This variable won't be effective when proximity sensor is available in the device.
-     */
-    private boolean mIgnoreTouchUserActivity = false;
-    private final IBinder mPokeLockToken = new Binder();
-
-    private IPowerManager mPowerManagerService;
-    private PowerManager.WakeLock mWakeLock;
-    private PowerManager.WakeLock mPartialWakeLock;
-    private PowerManager.WakeLock mProximityWakeLock;
-    private KeyguardManager mKeyguardManager;
-    private AccelerometerListener mAccelerometerListener;
-    private int mOrientation = AccelerometerListener.ORIENTATION_UNKNOWN;
-
-    private UpdateLock mUpdateLock;
-
-    // Broadcast receiver for various intent broadcasts (see onCreate())
-    private final BroadcastReceiver mReceiver = new PhoneAppBroadcastReceiver();
-
-    // Broadcast receiver purely for ACTION_MEDIA_BUTTON broadcasts
-    private final BroadcastReceiver mMediaButtonReceiver = new MediaButtonBroadcastReceiver();
-
-    /** boolean indicating restoring mute state on InCallScreen.onResume() */
-    private boolean mShouldRestoreMuteOnInCallResume;
-
-    /**
-     * The singleton OtaUtils instance used for OTASP calls.
-     *
-     * The OtaUtils instance is created lazily the first time we need to
-     * make an OTASP call, regardless of whether it's an interactive or
-     * non-interactive OTASP call.
-     */
-    public OtaUtils otaUtils;
-
-    // Following are the CDMA OTA information Objects used during OTA Call.
-    // cdmaOtaProvisionData object store static OTA information that needs
-    // to be maintained even during Slider open/close scenarios.
-    // cdmaOtaConfigData object stores configuration info to control visiblity
-    // of each OTA Screens.
-    // cdmaOtaScreenState object store OTA Screen State information.
-    public OtaUtils.CdmaOtaProvisionData cdmaOtaProvisionData;
-    public OtaUtils.CdmaOtaConfigData cdmaOtaConfigData;
-    public OtaUtils.CdmaOtaScreenState cdmaOtaScreenState;
-    public OtaUtils.CdmaOtaInCallScreenUiState cdmaOtaInCallScreenUiState;
-
-    // TTY feature enabled on this platform
-    private boolean mTtyEnabled;
-    // Current TTY operating mode selected by user
-    private int mPreferredTtyMode = Phone.TTY_MODE_OFF;
-
-    /**
-     * Set the restore mute state flag. Used when we are setting the mute state
-     * OUTSIDE of user interaction {@link PhoneUtils#startNewCall(Phone)}
-     */
-    /*package*/void setRestoreMuteOnInCallResume (boolean mode) {
-        mShouldRestoreMuteOnInCallResume = mode;
-    }
-
-    /**
-     * Get the restore mute state flag.
-     * This is used by the InCallScreen {@link InCallScreen#onResume()} to figure
-     * out if we need to restore the mute state for the current active call.
-     */
-    /*package*/boolean getRestoreMuteOnInCallResume () {
-        return mShouldRestoreMuteOnInCallResume;
-    }
-
-    Handler mHandler = new Handler() {
-        @Override
-        public void handleMessage(Message msg) {
-            PhoneConstants.State phoneState;
-            switch (msg.what) {
-                // Starts the SIP service. It's a no-op if SIP API is not supported
-                // on the deivce.
-                // TODO: Having the phone process host the SIP service is only
-                // temporary. Will move it to a persistent communication process
-                // later.
-                case EVENT_START_SIP_SERVICE:
-                    SipService.start(getApplicationContext());
-                    break;
-
-                // TODO: This event should be handled by the lock screen, just
-                // like the "SIM missing" and "Sim locked" cases (bug 1804111).
-                case EVENT_SIM_NETWORK_LOCKED:
-                    if (getResources().getBoolean(R.bool.ignore_sim_network_locked_events)) {
-                        // Some products don't have the concept of a "SIM network lock"
-                        Log.i(LOG_TAG, "Ignoring EVENT_SIM_NETWORK_LOCKED event; "
-                              + "not showing 'SIM network unlock' PIN entry screen");
-                    } else {
-                        // Normal case: show the "SIM network unlock" PIN entry screen.
-                        // The user won't be able to do anything else until
-                        // they enter a valid SIM network PIN.
-                        Log.i(LOG_TAG, "show sim depersonal panel");
-                        IccNetworkDepersonalizationPanel ndpPanel =
-                                new IccNetworkDepersonalizationPanel(PhoneApp.getInstance());
-                        ndpPanel.show();
-                    }
-                    break;
-
-                case EVENT_UPDATE_INCALL_NOTIFICATION:
-                    // Tell the NotificationMgr to update the "ongoing
-                    // call" icon in the status bar, if necessary.
-                    // Currently, this is triggered by a bluetooth headset
-                    // state change (since the status bar icon needs to
-                    // turn blue when bluetooth is active.)
-                    if (DBG) Log.d (LOG_TAG, "- updating in-call notification from handler...");
-                    notificationMgr.updateInCallNotification();
-                    break;
-
-                case EVENT_DATA_ROAMING_DISCONNECTED:
-                    notificationMgr.showDataDisconnectedRoaming();
-                    break;
-
-                case EVENT_DATA_ROAMING_OK:
-                    notificationMgr.hideDataDisconnectedRoaming();
-                    break;
-
-                case MMI_COMPLETE:
-                    onMMIComplete((AsyncResult) msg.obj);
-                    break;
-
-                case MMI_CANCEL:
-                    PhoneUtils.cancelMmiCode(phone);
-                    break;
-
-                case EVENT_WIRED_HEADSET_PLUG:
-                    // Since the presence of a wired headset or bluetooth affects the
-                    // speakerphone, update the "speaker" state.  We ONLY want to do
-                    // this on the wired headset connect / disconnect events for now
-                    // though, so we're only triggering on EVENT_WIRED_HEADSET_PLUG.
-
-                    phoneState = mCM.getState();
-                    // Do not change speaker state if phone is not off hook
-                    if (phoneState == PhoneConstants.State.OFFHOOK) {
-                        if (mBtHandsfree == null || !mBtHandsfree.isAudioOn()) {
-                            if (!isHeadsetPlugged()) {
-                                // if the state is "not connected", restore the speaker state.
-                                PhoneUtils.restoreSpeakerMode(getApplicationContext());
-                            } else {
-                                // if the state is "connected", force the speaker off without
-                                // storing the state.
-                                PhoneUtils.turnOnSpeaker(getApplicationContext(), false, false);
-                            }
-                        }
-                    }
-                    // Update the Proximity sensor based on headset state
-                    updateProximitySensorMode(phoneState);
-
-                    // Force TTY state update according to new headset state
-                    if (mTtyEnabled) {
-                        sendMessage(obtainMessage(EVENT_TTY_PREFERRED_MODE_CHANGED, 0));
-                    }
-                    break;
-
-                case EVENT_SIM_STATE_CHANGED:
-                    // Marks the event where the SIM goes into ready state.
-                    // Right now, this is only used for the PUK-unlocking
-                    // process.
-                    if (msg.obj.equals(IccCardConstants.INTENT_VALUE_ICC_READY)) {
-                        // when the right event is triggered and there
-                        // are UI objects in the foreground, we close
-                        // them to display the lock panel.
-                        if (mPUKEntryActivity != null) {
-                            mPUKEntryActivity.finish();
-                            mPUKEntryActivity = null;
-                        }
-                        if (mPUKEntryProgressDialog != null) {
-                            mPUKEntryProgressDialog.dismiss();
-                            mPUKEntryProgressDialog = null;
-                        }
-                    }
-                    break;
-
-                case EVENT_UNSOL_CDMA_INFO_RECORD:
-                    //TODO: handle message here;
-                    break;
-
-                case EVENT_DOCK_STATE_CHANGED:
-                    // If the phone is docked/undocked during a call, and no wired or BT headset
-                    // is connected: turn on/off the speaker accordingly.
-                    boolean inDockMode = false;
-                    if (mDockState != Intent.EXTRA_DOCK_STATE_UNDOCKED) {
-                        inDockMode = true;
-                    }
-                    if (VDBG) Log.d(LOG_TAG, "received EVENT_DOCK_STATE_CHANGED. Phone inDock = "
-                            + inDockMode);
-
-                    phoneState = mCM.getState();
-                    if (phoneState == PhoneConstants.State.OFFHOOK &&
-                            !isHeadsetPlugged() &&
-                            !(mBtHandsfree != null && mBtHandsfree.isAudioOn())) {
-                        PhoneUtils.turnOnSpeaker(getApplicationContext(), inDockMode, true);
-                        updateInCallScreen();  // Has no effect if the InCallScreen isn't visible
-                    }
-                    break;
-
-                case EVENT_TTY_PREFERRED_MODE_CHANGED:
-                    // TTY mode is only applied if a headset is connected
-                    int ttyMode;
-                    if (isHeadsetPlugged()) {
-                        ttyMode = mPreferredTtyMode;
-                    } else {
-                        ttyMode = Phone.TTY_MODE_OFF;
-                    }
-                    phone.setTTYMode(ttyMode, mHandler.obtainMessage(EVENT_TTY_MODE_SET));
-                    break;
-
-                case EVENT_TTY_MODE_GET:
-                    handleQueryTTYModeResponse(msg);
-                    break;
-
-                case EVENT_TTY_MODE_SET:
-                    handleSetTTYModeResponse(msg);
-                    break;
-            }
-        }
-    };
+public class PhoneApp extends Application {
+    PhoneGlobals mPhoneGlobals;
 
     public PhoneApp() {
-        sMe = this;
     }
 
     @Override
     public void onCreate() {
-        if (VDBG) Log.v(LOG_TAG, "onCreate()...");
-
-        ContentResolver resolver = getContentResolver();
-
-        // Cache the "voice capable" flag.
-        // This flag currently comes from a resource (which is
-        // overrideable on a per-product basis):
-        sVoiceCapable =
-                getResources().getBoolean(com.android.internal.R.bool.config_voice_capable);
-        // ...but this might eventually become a PackageManager "system
-        // feature" instead, in which case we'd do something like:
-        // sVoiceCapable =
-        //   getPackageManager().hasSystemFeature(PackageManager.FEATURE_TELEPHONY_VOICE_CALLS);
-
-        if (phone == null) {
-            // Initialize the telephony framework
-            PhoneFactory.makeDefaultPhones(this);
-
-            // Get the default phone
-            phone = PhoneFactory.getDefaultPhone();
-
-            // Start TelephonyDebugService After the default phone is created.
-            Intent intent = new Intent(this, TelephonyDebugService.class);
-            startService(intent);
-
-            mCM = CallManager.getInstance();
-            mCM.registerPhone(phone);
-
-            // Create the NotificationMgr singleton, which is used to display
-            // status bar icons and control other status bar behavior.
-            notificationMgr = NotificationMgr.init(this);
-
-            phoneMgr = PhoneInterfaceManager.init(this, phone);
-
-            mHandler.sendEmptyMessage(EVENT_START_SIP_SERVICE);
-
-            int phoneType = phone.getPhoneType();
-
-            if (phoneType == PhoneConstants.PHONE_TYPE_CDMA) {
-                // Create an instance of CdmaPhoneCallState and initialize it to IDLE
-                cdmaPhoneCallState = new CdmaPhoneCallState();
-                cdmaPhoneCallState.CdmaPhoneCallStateInit();
-            }
-
-            if (BluetoothAdapter.getDefaultAdapter() != null) {
-                // Start BluetoothHandsree even if device is not voice capable.
-                // The device can still support VOIP.
-                mBtHandsfree = BluetoothHandsfree.init(this, mCM);
-                startService(new Intent(this, BluetoothHeadsetService.class));
-            } else {
-                // Device is not bluetooth capable
-                mBtHandsfree = null;
-            }
-
-            ringer = Ringer.init(this);
-
-            // before registering for phone state changes
-            PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
-            mWakeLock = pm.newWakeLock(PowerManager.FULL_WAKE_LOCK
-                    | PowerManager.ACQUIRE_CAUSES_WAKEUP,
-                    LOG_TAG);
-            // lock used to keep the processor awake, when we don't care for the display.
-            mPartialWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK
-                    | PowerManager.ON_AFTER_RELEASE, LOG_TAG);
-            // Wake lock used to control proximity sensor behavior.
-            if ((pm.getSupportedWakeLockFlags()
-                 & PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK) != 0x0) {
-                mProximityWakeLock =
-                        pm.newWakeLock(PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK, LOG_TAG);
-            }
-            if (DBG) Log.d(LOG_TAG, "onCreate: mProximityWakeLock: " + mProximityWakeLock);
-
-            // create mAccelerometerListener only if we are using the proximity sensor
-            if (proximitySensorModeEnabled()) {
-                mAccelerometerListener = new AccelerometerListener(this, this);
-            }
-
-            mKeyguardManager = (KeyguardManager) getSystemService(Context.KEYGUARD_SERVICE);
-
-            // get a handle to the service so that we can use it later when we
-            // want to set the poke lock.
-            mPowerManagerService = IPowerManager.Stub.asInterface(
-                    ServiceManager.getService("power"));
-
-            // Get UpdateLock to suppress system-update related events (e.g. dialog show-up)
-            // during phone calls.
-            mUpdateLock = new UpdateLock("phone");
-
-            if (DBG) Log.d(LOG_TAG, "onCreate: mUpdateLock: " + mUpdateLock);
-
-            // Create the CallController singleton, which is the interface
-            // to the telephony layer for user-initiated telephony functionality
-            // (like making outgoing calls.)
-            callController = CallController.init(this);
-            // ...and also the InCallUiState instance, used by the CallController to
-            // keep track of some "persistent state" of the in-call UI.
-            inCallUiState = InCallUiState.init(this);
-
-            // Create the CallerInfoCache singleton, which remembers custom ring tone and
-            // send-to-voicemail settings.
-            //
-            // The asynchronous caching will start just after this call.
-            callerInfoCache = CallerInfoCache.init(this);
-
-            // Create the CallNotifer singleton, which handles
-            // asynchronous events from the telephony layer (like
-            // launching the incoming-call UI when an incoming call comes
-            // in.)
-            notifier = CallNotifier.init(this, phone, ringer, mBtHandsfree, new CallLogAsync());
-
-            // register for ICC status
-            IccCard sim = phone.getIccCard();
-            if (sim != null) {
-                if (VDBG) Log.v(LOG_TAG, "register for ICC status");
-                sim.registerForNetworkLocked(mHandler, EVENT_SIM_NETWORK_LOCKED, null);
-            }
-
-            // register for MMI/USSD
-            mCM.registerForMmiComplete(mHandler, MMI_COMPLETE, null);
-
-            // register connection tracking to PhoneUtils
-            PhoneUtils.initializeConnectionHandler(mCM);
-
-            // Read platform settings for TTY feature
-            mTtyEnabled = getResources().getBoolean(R.bool.tty_enabled);
-
-            // Register for misc other intent broadcasts.
-            IntentFilter intentFilter =
-                    new IntentFilter(Intent.ACTION_AIRPLANE_MODE_CHANGED);
-            intentFilter.addAction(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED);
-            intentFilter.addAction(BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED);
-            intentFilter.addAction(TelephonyIntents.ACTION_ANY_DATA_CONNECTION_STATE_CHANGED);
-            intentFilter.addAction(Intent.ACTION_HEADSET_PLUG);
-            intentFilter.addAction(Intent.ACTION_DOCK_EVENT);
-            intentFilter.addAction(TelephonyIntents.ACTION_SIM_STATE_CHANGED);
-            intentFilter.addAction(TelephonyIntents.ACTION_RADIO_TECHNOLOGY_CHANGED);
-            intentFilter.addAction(TelephonyIntents.ACTION_SERVICE_STATE_CHANGED);
-            intentFilter.addAction(TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED);
-            if (mTtyEnabled) {
-                intentFilter.addAction(TtyIntent.TTY_PREFERRED_MODE_CHANGE_ACTION);
-            }
-            intentFilter.addAction(AudioManager.RINGER_MODE_CHANGED_ACTION);
-            registerReceiver(mReceiver, intentFilter);
-
-            // Use a separate receiver for ACTION_MEDIA_BUTTON broadcasts,
-            // since we need to manually adjust its priority (to make sure
-            // we get these intents *before* the media player.)
-            IntentFilter mediaButtonIntentFilter =
-                    new IntentFilter(Intent.ACTION_MEDIA_BUTTON);
-            // TODO verify the independent priority doesn't need to be handled thanks to the
-            //  private intent handler registration
-            // Make sure we're higher priority than the media player's
-            // MediaButtonIntentReceiver (which currently has the default
-            // priority of zero; see apps/Music/AndroidManifest.xml.)
-            mediaButtonIntentFilter.setPriority(1);
-            //
-            registerReceiver(mMediaButtonReceiver, mediaButtonIntentFilter);
-            // register the component so it gets priority for calls
-            AudioManager am = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
-            am.registerMediaButtonEventReceiverForCalls(new ComponentName(this.getPackageName(),
-                    MediaButtonBroadcastReceiver.class.getName()));
-
-            //set the default values for the preferences in the phone.
-            PreferenceManager.setDefaultValues(this, R.xml.network_setting, false);
-
-            PreferenceManager.setDefaultValues(this, R.xml.call_feature_setting, false);
-
-            // Make sure the audio mode (along with some
-            // audio-mode-related state of our own) is initialized
-            // correctly, given the current state of the phone.
-            PhoneUtils.setAudioMode(mCM);
+        if (UserHandle.myUserId() == 0) {
+            // We are running as the primary user, so should bring up the
+            // global phone state.
+            mPhoneGlobals = new PhoneGlobals(this);
+            mPhoneGlobals.onCreate();
         }
-
-        if (TelephonyCapabilities.supportsOtasp(phone)) {
-            cdmaOtaProvisionData = new OtaUtils.CdmaOtaProvisionData();
-            cdmaOtaConfigData = new OtaUtils.CdmaOtaConfigData();
-            cdmaOtaScreenState = new OtaUtils.CdmaOtaScreenState();
-            cdmaOtaInCallScreenUiState = new OtaUtils.CdmaOtaInCallScreenUiState();
-        }
-
-        // XXX pre-load the SimProvider so that it's ready
-        resolver.getType(Uri.parse("content://icc/adn"));
-
-        // start with the default value to set the mute state.
-        mShouldRestoreMuteOnInCallResume = false;
-
-        // TODO: Register for Cdma Information Records
-        // phone.registerCdmaInformationRecord(mHandler, EVENT_UNSOL_CDMA_INFO_RECORD, null);
-
-        // Read TTY settings and store it into BP NV.
-        // AP owns (i.e. stores) the TTY setting in AP settings database and pushes the setting
-        // to BP at power up (BP does not need to make the TTY setting persistent storage).
-        // This way, there is a single owner (i.e AP) for the TTY setting in the phone.
-        if (mTtyEnabled) {
-            mPreferredTtyMode = android.provider.Settings.Secure.getInt(
-                    phone.getContext().getContentResolver(),
-                    android.provider.Settings.Secure.PREFERRED_TTY_MODE,
-                    Phone.TTY_MODE_OFF);
-            mHandler.sendMessage(mHandler.obtainMessage(EVENT_TTY_PREFERRED_MODE_CHANGED, 0));
-        }
-        // Read HAC settings and configure audio hardware
-        if (getResources().getBoolean(R.bool.hac_enabled)) {
-            int hac = android.provider.Settings.System.getInt(phone.getContext().getContentResolver(),
-                                                              android.provider.Settings.System.HEARING_AID,
-                                                              0);
-            AudioManager audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
-            audioManager.setParameter(CallFeaturesSetting.HAC_KEY, hac != 0 ?
-                                      CallFeaturesSetting.HAC_VAL_ON :
-                                      CallFeaturesSetting.HAC_VAL_OFF);
-        }
-   }
+    }
 
     @Override
     public void onConfigurationChanged(Configuration newConfig) {
-        if (newConfig.hardKeyboardHidden == Configuration.HARDKEYBOARDHIDDEN_NO) {
-            mIsHardKeyboardOpen = true;
-        } else {
-            mIsHardKeyboardOpen = false;
+        if (mPhoneGlobals != null) {
+            mPhoneGlobals.onConfigurationChanged(newConfig);
         }
-
-        // Update the Proximity sensor based on keyboard state
-        updateProximitySensorMode(mCM.getState());
         super.onConfigurationChanged(newConfig);
     }
-
-    /**
-     * Returns the singleton instance of the PhoneApp.
-     */
-    static PhoneApp getInstance() {
-        return sMe;
-    }
-
-    /**
-     * Returns the Phone associated with this instance
-     */
-    static Phone getPhone() {
-        return getInstance().phone;
-    }
-
-    Ringer getRinger() {
-        return ringer;
-    }
-
-    BluetoothHandsfree getBluetoothHandsfree() {
-        return mBtHandsfree;
-    }
-
-    /**
-     * Returns an Intent that can be used to go to the "Call log"
-     * UI (aka CallLogActivity) in the Contacts app.
-     *
-     * Watch out: there's no guarantee that the system has any activity to
-     * handle this intent.  (In particular there may be no "Call log" at
-     * all on on non-voice-capable devices.)
-     */
-    /* package */ static Intent createCallLogIntent() {
-        Intent intent = new Intent(Intent.ACTION_VIEW, null);
-        intent.setType("vnd.android.cursor.dir/calls");
-        return intent;
-    }
-
-    /**
-     * Return an Intent that can be used to bring up the in-call screen.
-     *
-     * This intent can only be used from within the Phone app, since the
-     * InCallScreen is not exported from our AndroidManifest.
-     */
-    /* package */ static Intent createInCallIntent() {
-        Intent intent = new Intent(Intent.ACTION_MAIN, null);
-        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
-                | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
-                | Intent.FLAG_ACTIVITY_NO_USER_ACTION);
-        intent.setClassName("com.android.phone", getCallScreenClassName());
-        return intent;
-    }
-
-    /**
-     * Variation of createInCallIntent() that also specifies whether the
-     * DTMF dialpad should be initially visible when the InCallScreen
-     * comes up.
-     */
-    /* package */ static Intent createInCallIntent(boolean showDialpad) {
-        Intent intent = createInCallIntent();
-        intent.putExtra(InCallScreen.SHOW_DIALPAD_EXTRA, showDialpad);
-        return intent;
-    }
-
-    /**
-     * Returns PendingIntent for hanging up ongoing phone call. This will typically be used from
-     * Notification context.
-     */
-    /* package */ static PendingIntent createHangUpOngoingCallPendingIntent(Context context) {
-        Intent intent = new Intent(PhoneApp.ACTION_HANG_UP_ONGOING_CALL, null,
-                context, NotificationBroadcastReceiver.class);
-        return PendingIntent.getBroadcast(context, 0, intent, 0);
-    }
-
-    /* package */ static PendingIntent getCallBackPendingIntent(Context context, String number) {
-        Intent intent = new Intent(ACTION_CALL_BACK_FROM_NOTIFICATION,
-                Uri.fromParts(Constants.SCHEME_TEL, number, null),
-                context, NotificationBroadcastReceiver.class);
-        return PendingIntent.getBroadcast(context, 0, intent, 0);
-    }
-
-    /* package */ static PendingIntent getSendSmsFromNotificationPendingIntent(
-            Context context, String number) {
-        Intent intent = new Intent(ACTION_SEND_SMS_FROM_NOTIFICATION,
-                Uri.fromParts(Constants.SCHEME_SMSTO, number, null),
-                context, NotificationBroadcastReceiver.class);
-        return PendingIntent.getBroadcast(context, 0, intent, 0);
-    }
-
-    private static String getCallScreenClassName() {
-        return InCallScreen.class.getName();
-    }
-
-    /**
-     * Starts the InCallScreen Activity.
-     */
-    /* package */ void displayCallScreen() {
-        if (VDBG) Log.d(LOG_TAG, "displayCallScreen()...");
-
-        // On non-voice-capable devices we shouldn't ever be trying to
-        // bring up the InCallScreen in the first place.
-        if (!sVoiceCapable) {
-            Log.w(LOG_TAG, "displayCallScreen() not allowed: non-voice-capable device",
-                  new Throwable("stack dump"));  // Include a stack trace since this warning
-                                                 // indicates a bug in our caller
-            return;
-        }
-
-        try {
-            startActivity(createInCallIntent());
-        } catch (ActivityNotFoundException e) {
-            // It's possible that the in-call UI might not exist (like on
-            // non-voice-capable devices), so don't crash if someone
-            // accidentally tries to bring it up...
-            Log.w(LOG_TAG, "displayCallScreen: transition to InCallScreen failed: " + e);
-        }
-        Profiler.callScreenRequested();
-    }
-
-    boolean isSimPinEnabled() {
-        return mIsSimPinEnabled;
-    }
-
-    boolean authenticateAgainstCachedSimPin(String pin) {
-        return (mCachedSimPin != null && mCachedSimPin.equals(pin));
-    }
-
-    void setCachedSimPin(String pin) {
-        mCachedSimPin = pin;
-    }
-
-    void setInCallScreenInstance(InCallScreen inCallScreen) {
-        mInCallScreen = inCallScreen;
-    }
-
-    /**
-     * @return true if the in-call UI is running as the foreground
-     * activity.  (In other words, from the perspective of the
-     * InCallScreen activity, return true between onResume() and
-     * onPause().)
-     *
-     * Note this method will return false if the screen is currently off,
-     * even if the InCallScreen *was* in the foreground just before the
-     * screen turned off.  (This is because the foreground activity is
-     * always "paused" while the screen is off.)
-     */
-    boolean isShowingCallScreen() {
-        if (mInCallScreen == null) return false;
-        return mInCallScreen.isForegroundActivity();
-    }
-
-    /**
-     * @return true if the in-call UI is running as the foreground activity, or,
-     * it went to background due to screen being turned off. This might be useful
-     * to determine if the in-call screen went to background because of other
-     * activities, or its proximity sensor state or manual power-button press.
-     *
-     * Here are some examples.
-     *
-     * - If you want to know if the activity is in foreground or screen is turned off
-     *   from the in-call UI (i.e. though it is not "foreground" anymore it will become
-     *   so after screen being turned on), check
-     *   {@link #isShowingCallScreenForProximity()} is true or not.
-     *   {@link #updateProximitySensorMode(com.android.internal.telephony.PhoneConstants.State)} is
-     *   doing this.
-     *
-     * - If you want to know if the activity is not in foreground just because screen
-     *   is turned off (not due to other activity's interference), check
-     *   {@link #isShowingCallScreen()} is false *and* {@link #isShowingCallScreenForProximity()}
-     *   is true. InCallScreen#onDisconnect() is doing this check.
-     *
-     * @see #isShowingCallScreen()
-     *
-     * TODO: come up with better naming..
-     */
-    boolean isShowingCallScreenForProximity() {
-        if (mInCallScreen == null) return false;
-        return mInCallScreen.isForegroundActivityForProximity();
-    }
-
-    /**
-     * Dismisses the in-call UI.
-     *
-     * This also ensures that you won't be able to get back to the in-call
-     * UI via the BACK button (since this call removes the InCallScreen
-     * from the activity history.)
-     * For OTA Call, it call InCallScreen api to handle OTA Call End scenario
-     * to display OTA Call End screen.
-     */
-    /* package */ void dismissCallScreen() {
-        if (mInCallScreen != null) {
-            if ((TelephonyCapabilities.supportsOtasp(phone)) &&
-                    (mInCallScreen.isOtaCallInActiveState()
-                    || mInCallScreen.isOtaCallInEndState()
-                    || ((cdmaOtaScreenState != null)
-                    && (cdmaOtaScreenState.otaScreenState
-                            != CdmaOtaScreenState.OtaScreenState.OTA_STATUS_UNDEFINED)))) {
-                // TODO: During OTA Call, display should not become dark to
-                // allow user to see OTA UI update. Phone app needs to hold
-                // a SCREEN_DIM_WAKE_LOCK wake lock during the entire OTA call.
-                wakeUpScreen();
-                // If InCallScreen is not in foreground we resume it to show the OTA call end screen
-                // Fire off the InCallScreen intent
-                displayCallScreen();
-
-                mInCallScreen.handleOtaCallEnd();
-                return;
-            } else {
-                mInCallScreen.finish();
-            }
-        }
-    }
-
-    /**
-     * Handles OTASP-related events from the telephony layer.
-     *
-     * While an OTASP call is active, the CallNotifier forwards
-     * OTASP-related telephony events to this method.
-     */
-    void handleOtaspEvent(Message msg) {
-        if (DBG) Log.d(LOG_TAG, "handleOtaspEvent(message " + msg + ")...");
-
-        if (otaUtils == null) {
-            // We shouldn't be getting OTASP events without ever
-            // having started the OTASP call in the first place!
-            Log.w(LOG_TAG, "handleOtaEvents: got an event but otaUtils is null! "
-                  + "message = " + msg);
-            return;
-        }
-
-        otaUtils.onOtaProvisionStatusChanged((AsyncResult) msg.obj);
-    }
-
-    /**
-     * Similarly, handle the disconnect event of an OTASP call
-     * by forwarding it to the OtaUtils instance.
-     */
-    /* package */ void handleOtaspDisconnect() {
-        if (DBG) Log.d(LOG_TAG, "handleOtaspDisconnect()...");
-
-        if (otaUtils == null) {
-            // We shouldn't be getting OTASP events without ever
-            // having started the OTASP call in the first place!
-            Log.w(LOG_TAG, "handleOtaspDisconnect: otaUtils is null!");
-            return;
-        }
-
-        otaUtils.onOtaspDisconnect();
-    }
-
-    /**
-     * Sets the activity responsible for un-PUK-blocking the device
-     * so that we may close it when we receive a positive result.
-     * mPUKEntryActivity is also used to indicate to the device that
-     * we are trying to un-PUK-lock the phone. In other words, iff
-     * it is NOT null, then we are trying to unlock and waiting for
-     * the SIM to move to READY state.
-     *
-     * @param activity is the activity to close when PUK has
-     * finished unlocking. Can be set to null to indicate the unlock
-     * or SIM READYing process is over.
-     */
-    void setPukEntryActivity(Activity activity) {
-        mPUKEntryActivity = activity;
-    }
-
-    Activity getPUKEntryActivity() {
-        return mPUKEntryActivity;
-    }
-
-    /**
-     * Sets the dialog responsible for notifying the user of un-PUK-
-     * blocking - SIM READYing progress, so that we may dismiss it
-     * when we receive a positive result.
-     *
-     * @param dialog indicates the progress dialog informing the user
-     * of the state of the device.  Dismissed upon completion of
-     * READYing process
-     */
-    void setPukEntryProgressDialog(ProgressDialog dialog) {
-        mPUKEntryProgressDialog = dialog;
-    }
-
-    ProgressDialog getPUKEntryProgressDialog() {
-        return mPUKEntryProgressDialog;
-    }
-
-    /**
-     * Controls how quickly the screen times out.
-     *
-     * This is no-op when the device supports proximity sensor.
-     *
-     * The poke lock controls how long it takes before the screen powers
-     * down, and therefore has no immediate effect when the current
-     * WakeState (see {@link PhoneApp#requestWakeState}) is FULL.
-     * If we're in a state where the screen *is* allowed to turn off,
-     * though, the poke lock will determine the timeout interval (long or
-     * short).
-     */
-    /* package */ void setScreenTimeout(ScreenTimeoutDuration duration) {
-        if (VDBG) Log.d(LOG_TAG, "setScreenTimeout(" + duration + ")...");
-
-        // stick with default timeout if we are using the proximity sensor
-        if (proximitySensorModeEnabled()) {
-            return;
-        }
-
-        // make sure we don't set the poke lock repeatedly so that we
-        // avoid triggering the userActivity calls in
-        // PowerManagerService.setPokeLock().
-        if (duration == mScreenTimeoutDuration) {
-            return;
-        }
-        mScreenTimeoutDuration = duration;
-        updatePokeLock();
-    }
-
-    /**
-     * Update the state of the poke lock held by the phone app,
-     * based on the current desired screen timeout and the
-     * current "ignore user activity on touch" flag.
-     */
-    private void updatePokeLock() {
-        // Caller must take care of the check. This block is purely for safety.
-        if (proximitySensorModeEnabled()) {
-            Log.wtf(LOG_TAG, "PokeLock should not be used when proximity sensor is available on"
-                    + " the device.");
-            return;
-        }
-
-        // This is kind of convoluted, but the basic thing to remember is
-        // that the poke lock just sends a message to the screen to tell
-        // it to stay on for a while.
-        // The default is 0, for a long timeout and should be set that way
-        // when we are heading back into a the keyguard / screen off
-        // state, and also when we're trying to keep the screen alive
-        // while ringing.  We'll also want to ignore the cheek events
-        // regardless of the timeout duration.
-        // The short timeout is really used whenever we want to give up
-        // the screen lock, such as when we're in call.
-        int pokeLockSetting = 0;
-        switch (mScreenTimeoutDuration) {
-            case SHORT:
-                // Set the poke lock to timeout the display after a short
-                // timeout (5s). This ensures that the screen goes to sleep
-                // as soon as acceptably possible after we the wake lock
-                // has been released.
-                pokeLockSetting |= LocalPowerManager.POKE_LOCK_SHORT_TIMEOUT;
-                break;
-
-            case MEDIUM:
-                // Set the poke lock to timeout the display after a medium
-                // timeout (15s). This ensures that the screen goes to sleep
-                // as soon as acceptably possible after we the wake lock
-                // has been released.
-                pokeLockSetting |= LocalPowerManager.POKE_LOCK_MEDIUM_TIMEOUT;
-                break;
-
-            case DEFAULT:
-            default:
-                // set the poke lock to timeout the display after a long
-                // delay by default.
-                // TODO: it may be nice to be able to disable cheek presses
-                // for long poke locks (emergency dialer, for instance).
-                break;
-        }
-
-        if (mIgnoreTouchUserActivity) {
-            pokeLockSetting |= LocalPowerManager.POKE_LOCK_IGNORE_TOUCH_EVENTS;
-        }
-
-        // Send the request
-        try {
-            mPowerManagerService.setPokeLock(pokeLockSetting, mPokeLockToken, LOG_TAG);
-        } catch (RemoteException e) {
-            Log.w(LOG_TAG, "mPowerManagerService.setPokeLock() failed: " + e);
-        }
-    }
-
-    /**
-     * Controls whether or not the screen is allowed to sleep.
-     *
-     * Once sleep is allowed (WakeState is SLEEP), it will rely on the
-     * settings for the poke lock to determine when to timeout and let
-     * the device sleep {@link PhoneApp#setScreenTimeout}.
-     *
-     * @param ws tells the device to how to wake.
-     */
-    /* package */ void requestWakeState(WakeState ws) {
-        if (VDBG) Log.d(LOG_TAG, "requestWakeState(" + ws + ")...");
-        synchronized (this) {
-            if (mWakeState != ws) {
-                switch (ws) {
-                    case PARTIAL:
-                        // acquire the processor wake lock, and release the FULL
-                        // lock if it is being held.
-                        mPartialWakeLock.acquire();
-                        if (mWakeLock.isHeld()) {
-                            mWakeLock.release();
-                        }
-                        break;
-                    case FULL:
-                        // acquire the full wake lock, and release the PARTIAL
-                        // lock if it is being held.
-                        mWakeLock.acquire();
-                        if (mPartialWakeLock.isHeld()) {
-                            mPartialWakeLock.release();
-                        }
-                        break;
-                    case SLEEP:
-                    default:
-                        // release both the PARTIAL and FULL locks.
-                        if (mWakeLock.isHeld()) {
-                            mWakeLock.release();
-                        }
-                        if (mPartialWakeLock.isHeld()) {
-                            mPartialWakeLock.release();
-                        }
-                        break;
-                }
-                mWakeState = ws;
-            }
-        }
-    }
-
-    /**
-     * If we are not currently keeping the screen on, then poke the power
-     * manager to wake up the screen for the user activity timeout duration.
-     */
-    /* package */ void wakeUpScreen() {
-        synchronized (this) {
-            if (mWakeState == WakeState.SLEEP) {
-                if (DBG) Log.d(LOG_TAG, "pulse screen lock");
-                try {
-                    mPowerManagerService.userActivityWithForce(SystemClock.uptimeMillis(), false, true);
-                } catch (RemoteException ex) {
-                    // Ignore -- the system process is dead.
-                }
-            }
-        }
-    }
-
-    /**
-     * Sets the wake state and screen timeout based on the current state
-     * of the phone, and the current state of the in-call UI.
-     *
-     * This method is a "UI Policy" wrapper around
-     * {@link PhoneApp#requestWakeState} and {@link PhoneApp#setScreenTimeout}.
-     *
-     * It's safe to call this method regardless of the state of the Phone
-     * (e.g. whether or not it's idle), and regardless of the state of the
-     * Phone UI (e.g. whether or not the InCallScreen is active.)
-     */
-    /* package */ void updateWakeState() {
-        PhoneConstants.State state = mCM.getState();
-
-        // True if the in-call UI is the foreground activity.
-        // (Note this will be false if the screen is currently off,
-        // since in that case *no* activity is in the foreground.)
-        boolean isShowingCallScreen = isShowingCallScreen();
-
-        // True if the InCallScreen's DTMF dialer is currently opened.
-        // (Note this does NOT imply whether or not the InCallScreen
-        // itself is visible.)
-        boolean isDialerOpened = (mInCallScreen != null) && mInCallScreen.isDialerOpened();
-
-        // True if the speakerphone is in use.  (If so, we *always* use
-        // the default timeout.  Since the user is obviously not holding
-        // the phone up to his/her face, we don't need to worry about
-        // false touches, and thus don't need to turn the screen off so
-        // aggressively.)
-        // Note that we need to make a fresh call to this method any
-        // time the speaker state changes.  (That happens in
-        // PhoneUtils.turnOnSpeaker().)
-        boolean isSpeakerInUse = (state == PhoneConstants.State.OFFHOOK) && PhoneUtils.isSpeakerOn(this);
-
-        // TODO (bug 1440854): The screen timeout *might* also need to
-        // depend on the bluetooth state, but this isn't as clear-cut as
-        // the speaker state (since while using BT it's common for the
-        // user to put the phone straight into a pocket, in which case the
-        // timeout should probably still be short.)
-
-        if (DBG) Log.d(LOG_TAG, "updateWakeState: callscreen " + isShowingCallScreen
-                       + ", dialer " + isDialerOpened
-                       + ", speaker " + isSpeakerInUse + "...");
-
-        //
-        // (1) Set the screen timeout.
-        //
-        // Note that the "screen timeout" value we determine here is
-        // meaningless if the screen is forced on (see (2) below.)
-        //
-
-        // Historical note: In froyo and earlier, we checked here for a special
-        // case: the in-call UI being active, the speaker off, and the DTMF dialpad
-        // not visible.  In that case, with no touchable UI onscreen at all (for
-        // non-prox-sensor devices at least), we could assume the user was probably
-        // holding the phone up to their face and *not* actually looking at the
-        // screen.  So we'd switch to a special screen timeout value
-        // (ScreenTimeoutDuration.MEDIUM), purely to save battery life.
-        //
-        // On current devices, we can rely on the proximity sensor to turn the
-        // screen off in this case, so we use the system-wide default timeout
-        // unconditionally.
-        setScreenTimeout(ScreenTimeoutDuration.DEFAULT);
-
-        //
-        // (2) Decide whether to force the screen on or not.
-        //
-        // Force the screen to be on if the phone is ringing or dialing,
-        // or if we're displaying the "Call ended" UI for a connection in
-        // the "disconnected" state.
-        //
-        boolean isRinging = (state == PhoneConstants.State.RINGING);
-        boolean isDialing = (phone.getForegroundCall().getState() == Call.State.DIALING);
-        boolean showingDisconnectedConnection =
-                PhoneUtils.hasDisconnectedConnections(phone) && isShowingCallScreen;
-        boolean keepScreenOn = isRinging || isDialing || showingDisconnectedConnection;
-        if (DBG) Log.d(LOG_TAG, "updateWakeState: keepScreenOn = " + keepScreenOn
-                       + " (isRinging " + isRinging
-                       + ", isDialing " + isDialing
-                       + ", showingDisc " + showingDisconnectedConnection + ")");
-        // keepScreenOn == true means we'll hold a full wake lock:
-        requestWakeState(keepScreenOn ? WakeState.FULL : WakeState.SLEEP);
-    }
-
-    /**
-     * Wrapper around the PowerManagerService.preventScreenOn() API.
-     * This allows the in-call UI to prevent the screen from turning on
-     * even if a subsequent call to updateWakeState() causes us to acquire
-     * a full wake lock.
-     */
-    /* package */ void preventScreenOn(boolean prevent) {
-        if (VDBG) Log.d(LOG_TAG, "- preventScreenOn(" + prevent + ")...");
-        try {
-            mPowerManagerService.preventScreenOn(prevent);
-        } catch (RemoteException e) {
-            Log.w(LOG_TAG, "mPowerManagerService.preventScreenOn() failed: " + e);
-        }
-    }
-
-    /**
-     * Sets or clears the flag that tells the PowerManager that touch
-     * (and cheek) events should NOT be considered "user activity".
-     *
-     * This method is no-op when proximity sensor is available on the device.
-     *
-     * Since the in-call UI is totally insensitive to touch in most
-     * states, we set this flag whenever the InCallScreen is in the
-     * foreground.  (Otherwise, repeated unintentional touches could
-     * prevent the device from going to sleep.)
-     *
-     * There *are* some some touch events that really do count as user
-     * activity, though.  For those, we need to manually poke the
-     * PowerManager's userActivity method; see pokeUserActivity().
-     */
-    /* package */ void setIgnoreTouchUserActivity(boolean ignore) {
-        if (VDBG) Log.d(LOG_TAG, "setIgnoreTouchUserActivity(" + ignore + ")...");
-        // stick with default timeout if we are using the proximity sensor
-        if (proximitySensorModeEnabled()) {
-            return;
-        }
-
-        mIgnoreTouchUserActivity = ignore;
-        updatePokeLock();
-    }
-
-    /**
-     * Manually pokes the PowerManager's userActivity method.  Since we
-     * hold the POKE_LOCK_IGNORE_TOUCH_EVENTS poke lock while
-     * the InCallScreen is active, we need to do this for touch events
-     * that really do count as user activity (like pressing any
-     * onscreen UI elements.)
-     */
-    /* package */ void pokeUserActivity() {
-        if (VDBG) Log.d(LOG_TAG, "pokeUserActivity()...");
-        try {
-            mPowerManagerService.userActivity(SystemClock.uptimeMillis(), false);
-        } catch (RemoteException e) {
-            Log.w(LOG_TAG, "mPowerManagerService.userActivity() failed: " + e);
-        }
-    }
-
-    /**
-     * Set when a new outgoing call is beginning, so we can update
-     * the proximity sensor state.
-     * Cleared when the InCallScreen is no longer in the foreground,
-     * in case the call fails without changing the telephony state.
-     */
-    /* package */ void setBeginningCall(boolean beginning) {
-        // Note that we are beginning a new call, for proximity sensor support
-        mBeginningCall = beginning;
-        // Update the Proximity sensor based on mBeginningCall state
-        updateProximitySensorMode(mCM.getState());
-    }
-
-    /**
-     * Updates the wake lock used to control proximity sensor behavior,
-     * based on the current state of the phone.  This method is called
-     * from the CallNotifier on any phone state change.
-     *
-     * On devices that have a proximity sensor, to avoid false touches
-     * during a call, we hold a PROXIMITY_SCREEN_OFF_WAKE_LOCK wake lock
-     * whenever the phone is off hook.  (When held, that wake lock causes
-     * the screen to turn off automatically when the sensor detects an
-     * object close to the screen.)
-     *
-     * This method is a no-op for devices that don't have a proximity
-     * sensor.
-     *
-     * Note this method doesn't care if the InCallScreen is the foreground
-     * activity or not.  That's because we want the proximity sensor to be
-     * enabled any time the phone is in use, to avoid false cheek events
-     * for whatever app you happen to be running.
-     *
-     * Proximity wake lock will *not* be held if any one of the
-     * conditions is true while on a call:
-     * 1) If the audio is routed via Bluetooth
-     * 2) If a wired headset is connected
-     * 3) if the speaker is ON
-     * 4) If the slider is open(i.e. the hardkeyboard is *not* hidden)
-     *
-     * @param state current state of the phone (see {@link Phone#State})
-     */
-    /* package */ void updateProximitySensorMode(PhoneConstants.State state) {
-        if (VDBG) Log.d(LOG_TAG, "updateProximitySensorMode: state = " + state);
-
-        if (proximitySensorModeEnabled()) {
-            synchronized (mProximityWakeLock) {
-                // turn proximity sensor off and turn screen on immediately if
-                // we are using a headset, the keyboard is open, or the device
-                // is being held in a horizontal position.
-                boolean screenOnImmediately = (isHeadsetPlugged()
-                            || PhoneUtils.isSpeakerOn(this)
-                            || ((mBtHandsfree != null) && mBtHandsfree.isAudioOn())
-                            || mIsHardKeyboardOpen);
-
-                // We do not keep the screen off when the user is outside in-call screen and we are
-                // horizontal, but we do not force it on when we become horizontal until the
-                // proximity sensor goes negative.
-                boolean horizontal =
-                        (mOrientation == AccelerometerListener.ORIENTATION_HORIZONTAL);
-                screenOnImmediately |= !isShowingCallScreenForProximity() && horizontal;
-
-                // We do not keep the screen off when dialpad is visible, we are horizontal, and
-                // the in-call screen is being shown.
-                // At that moment we're pretty sure users want to use it, instead of letting the
-                // proximity sensor turn off the screen by their hands.
-                boolean dialpadVisible = false;
-                if (mInCallScreen != null) {
-                    dialpadVisible =
-                            mInCallScreen.getUpdatedInCallControlState().dialpadEnabled
-                            && mInCallScreen.getUpdatedInCallControlState().dialpadVisible
-                            && isShowingCallScreen();
-                }
-                screenOnImmediately |= dialpadVisible && horizontal;
-
-                if (((state == PhoneConstants.State.OFFHOOK) || mBeginningCall) && !screenOnImmediately) {
-                    // Phone is in use!  Arrange for the screen to turn off
-                    // automatically when the sensor detects a close object.
-                    if (!mProximityWakeLock.isHeld()) {
-                        if (DBG) Log.d(LOG_TAG, "updateProximitySensorMode: acquiring...");
-                        mProximityWakeLock.acquire();
-                    } else {
-                        if (VDBG) Log.d(LOG_TAG, "updateProximitySensorMode: lock already held.");
-                    }
-                } else {
-                    // Phone is either idle, or ringing.  We don't want any
-                    // special proximity sensor behavior in either case.
-                    if (mProximityWakeLock.isHeld()) {
-                        if (DBG) Log.d(LOG_TAG, "updateProximitySensorMode: releasing...");
-                        // Wait until user has moved the phone away from his head if we are
-                        // releasing due to the phone call ending.
-                        // Qtherwise, turn screen on immediately
-                        int flags =
-                            (screenOnImmediately ? 0 : PowerManager.WAIT_FOR_PROXIMITY_NEGATIVE);
-                        mProximityWakeLock.release(flags);
-                    } else {
-                        if (VDBG) {
-                            Log.d(LOG_TAG, "updateProximitySensorMode: lock already released.");
-                        }
-                    }
-                }
-            }
-        }
-    }
-
-    @Override
-    public void orientationChanged(int orientation) {
-        mOrientation = orientation;
-        updateProximitySensorMode(mCM.getState());
-    }
-
-    /**
-     * Notifies the phone app when the phone state changes.
-     *
-     * This method will updates various states inside Phone app (e.g. proximity sensor mode,
-     * accelerometer listener state, update-lock state, etc.)
-     */
-    /* package */ void updatePhoneState(PhoneConstants.State state) {
-        if (state != mLastPhoneState) {
-            mLastPhoneState = state;
-            updateProximitySensorMode(state);
-
-            // Try to acquire or release UpdateLock.
-            //
-            // Watch out: we don't release the lock here when the screen is still in foreground.
-            // At that time InCallScreen will release it on onPause().
-            if (state != PhoneConstants.State.IDLE) {
-                // UpdateLock is a recursive lock, while we may get "acquire" request twice and
-                // "release" request once for a single call (RINGING + OFFHOOK and IDLE).
-                // We need to manually ensure the lock is just acquired once for each (and this
-                // will prevent other possible buggy situations too).
-                if (!mUpdateLock.isHeld()) {
-                    mUpdateLock.acquire();
-                }
-            } else {
-                if (!isShowingCallScreen()) {
-                    if (!mUpdateLock.isHeld()) {
-                        mUpdateLock.release();
-                    }
-                } else {
-                    // For this case InCallScreen will take care of the release() call.
-                }
-            }
-
-            if (mAccelerometerListener != null) {
-                // use accelerometer to augment proximity sensor when in call
-                mOrientation = AccelerometerListener.ORIENTATION_UNKNOWN;
-                mAccelerometerListener.enable(state == PhoneConstants.State.OFFHOOK);
-            }
-            // clear our beginning call flag
-            mBeginningCall = false;
-            // While we are in call, the in-call screen should dismiss the keyguard.
-            // This allows the user to press Home to go directly home without going through
-            // an insecure lock screen.
-            // But we do not want to do this if there is no active call so we do not
-            // bypass the keyguard if the call is not answered or declined.
-            if (mInCallScreen != null) {
-                mInCallScreen.updateKeyguardPolicy(state == PhoneConstants.State.OFFHOOK);
-            }
-        }
-    }
-
-    /* package */ PhoneConstants.State getPhoneState() {
-        return mLastPhoneState;
-    }
-
-    /**
-     * Returns UpdateLock object.
-     */
-    /* package */ UpdateLock getUpdateLock() {
-        return mUpdateLock;
-    }
-
-    /**
-     * @return true if this device supports the "proximity sensor
-     * auto-lock" feature while in-call (see updateProximitySensorMode()).
-     */
-    /* package */ boolean proximitySensorModeEnabled() {
-        return (mProximityWakeLock != null);
-    }
-
-    KeyguardManager getKeyguardManager() {
-        return mKeyguardManager;
-    }
-
-    private void onMMIComplete(AsyncResult r) {
-        if (VDBG) Log.d(LOG_TAG, "onMMIComplete()...");
-        MmiCode mmiCode = (MmiCode) r.result;
-        PhoneUtils.displayMMIComplete(phone, getInstance(), mmiCode, null, null);
-    }
-
-    private void initForNewRadioTechnology() {
-        if (DBG) Log.d(LOG_TAG, "initForNewRadioTechnology...");
-
-         if (phone.getPhoneType() == PhoneConstants.PHONE_TYPE_CDMA) {
-            // Create an instance of CdmaPhoneCallState and initialize it to IDLE
-            cdmaPhoneCallState = new CdmaPhoneCallState();
-            cdmaPhoneCallState.CdmaPhoneCallStateInit();
-        }
-        if (TelephonyCapabilities.supportsOtasp(phone)) {
-            //create instances of CDMA OTA data classes
-            if (cdmaOtaProvisionData == null) {
-                cdmaOtaProvisionData = new OtaUtils.CdmaOtaProvisionData();
-            }
-            if (cdmaOtaConfigData == null) {
-                cdmaOtaConfigData = new OtaUtils.CdmaOtaConfigData();
-            }
-            if (cdmaOtaScreenState == null) {
-                cdmaOtaScreenState = new OtaUtils.CdmaOtaScreenState();
-            }
-            if (cdmaOtaInCallScreenUiState == null) {
-                cdmaOtaInCallScreenUiState = new OtaUtils.CdmaOtaInCallScreenUiState();
-            }
-        } else {
-            //Clean up OTA data in GSM/UMTS. It is valid only for CDMA
-            clearOtaState();
-        }
-
-        ringer.updateRingerContextAfterRadioTechnologyChange(this.phone);
-        notifier.updateCallNotifierRegistrationsAfterRadioTechnologyChange();
-        if (mBtHandsfree != null) {
-            mBtHandsfree.updateBtHandsfreeAfterRadioTechnologyChange();
-        }
-        if (mInCallScreen != null) {
-            mInCallScreen.updateAfterRadioTechnologyChange();
-        }
-
-        // Update registration for ICC status after radio technology change
-        IccCard sim = phone.getIccCard();
-        if (sim != null) {
-            if (DBG) Log.d(LOG_TAG, "Update registration for ICC status...");
-
-            //Register all events new to the new active phone
-            sim.registerForNetworkLocked(mHandler, EVENT_SIM_NETWORK_LOCKED, null);
-        }
-    }
-
-
-    /**
-     * @return true if a wired headset is currently plugged in.
-     *
-     * @see Intent.ACTION_HEADSET_PLUG (which we listen for in mReceiver.onReceive())
-     */
-    boolean isHeadsetPlugged() {
-        return mIsHeadsetPlugged;
-    }
-
-    /**
-     * @return true if the onscreen UI should currently be showing the
-     * special "bluetooth is active" indication in a couple of places (in
-     * which UI elements turn blue and/or show the bluetooth logo.)
-     *
-     * This depends on the BluetoothHeadset state *and* the current
-     * telephony state; see shouldShowBluetoothIndication().
-     *
-     * @see CallCard
-     * @see NotificationMgr.updateInCallNotification
-     */
-    /* package */ boolean showBluetoothIndication() {
-        return mShowBluetoothIndication;
-    }
-
-    /**
-     * Recomputes the mShowBluetoothIndication flag based on the current
-     * bluetooth state and current telephony state.
-     *
-     * This needs to be called any time the bluetooth headset state or the
-     * telephony state changes.
-     *
-     * @param forceUiUpdate if true, force the UI elements that care
-     *                      about this flag to update themselves.
-     */
-    /* package */ void updateBluetoothIndication(boolean forceUiUpdate) {
-        mShowBluetoothIndication = shouldShowBluetoothIndication(mBluetoothHeadsetState,
-                                                                 mBluetoothHeadsetAudioState,
-                                                                 mCM);
-        if (forceUiUpdate) {
-            // Post Handler messages to the various components that might
-            // need to be refreshed based on the new state.
-            if (isShowingCallScreen()) mInCallScreen.requestUpdateBluetoothIndication();
-            if (DBG) Log.d (LOG_TAG, "- updating in-call notification for BT state change...");
-            mHandler.sendEmptyMessage(EVENT_UPDATE_INCALL_NOTIFICATION);
-        }
-
-        // Update the Proximity sensor based on Bluetooth audio state
-        updateProximitySensorMode(mCM.getState());
-    }
-
-    /**
-     * UI policy helper function for the couple of places in the UI that
-     * have some way of indicating that "bluetooth is in use."
-     *
-     * @return true if the onscreen UI should indicate that "bluetooth is in use",
-     *         based on the specified bluetooth headset state, and the
-     *         current state of the phone.
-     * @see showBluetoothIndication()
-     */
-    private static boolean shouldShowBluetoothIndication(int bluetoothState,
-                                                         int bluetoothAudioState,
-                                                         CallManager cm) {
-        // We want the UI to indicate that "bluetooth is in use" in two
-        // slightly different cases:
-        //
-        // (a) The obvious case: if a bluetooth headset is currently in
-        //     use for an ongoing call.
-        //
-        // (b) The not-so-obvious case: if an incoming call is ringing,
-        //     and we expect that audio *will* be routed to a bluetooth
-        //     headset once the call is answered.
-
-        switch (cm.getState()) {
-            case OFFHOOK:
-                // This covers normal active calls, and also the case if
-                // the foreground call is DIALING or ALERTING.  In this
-                // case, bluetooth is considered "active" if a headset
-                // is connected *and* audio is being routed to it.
-                return ((bluetoothState == BluetoothHeadset.STATE_CONNECTED)
-                        && (bluetoothAudioState == BluetoothHeadset.STATE_AUDIO_CONNECTED));
-
-            case RINGING:
-                // If an incoming call is ringing, we're *not* yet routing
-                // audio to the headset (since there's no in-call audio
-                // yet!)  In this case, if a bluetooth headset is
-                // connected at all, we assume that it'll become active
-                // once the user answers the phone.
-                return (bluetoothState == BluetoothHeadset.STATE_CONNECTED);
-
-            default:  // Presumably IDLE
-                return false;
-        }
-    }
-
-
-    /**
-     * Receiver for misc intent broadcasts the Phone app cares about.
-     */
-    private class PhoneAppBroadcastReceiver extends BroadcastReceiver {
-        @Override
-        public void onReceive(Context context, Intent intent) {
-            String action = intent.getAction();
-            if (action.equals(Intent.ACTION_AIRPLANE_MODE_CHANGED)) {
-                boolean enabled = System.getInt(getContentResolver(),
-                        System.AIRPLANE_MODE_ON, 0) == 0;
-                phone.setRadioPower(enabled);
-            } else if (action.equals(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED)) {
-                mBluetoothHeadsetState = intent.getIntExtra(BluetoothHeadset.EXTRA_STATE,
-                                                          BluetoothHeadset.STATE_DISCONNECTED);
-                if (VDBG) Log.d(LOG_TAG, "mReceiver: HEADSET_STATE_CHANGED_ACTION");
-                if (VDBG) Log.d(LOG_TAG, "==> new state: " + mBluetoothHeadsetState);
-                updateBluetoothIndication(true);  // Also update any visible UI if necessary
-            } else if (action.equals(BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED)) {
-                mBluetoothHeadsetAudioState =
-                        intent.getIntExtra(BluetoothHeadset.EXTRA_STATE,
-                                           BluetoothHeadset.STATE_AUDIO_DISCONNECTED);
-                if (VDBG) Log.d(LOG_TAG, "mReceiver: HEADSET_AUDIO_STATE_CHANGED_ACTION");
-                if (VDBG) Log.d(LOG_TAG, "==> new state: " + mBluetoothHeadsetAudioState);
-                updateBluetoothIndication(true);  // Also update any visible UI if necessary
-            } else if (action.equals(TelephonyIntents.ACTION_ANY_DATA_CONNECTION_STATE_CHANGED)) {
-                if (VDBG) Log.d(LOG_TAG, "mReceiver: ACTION_ANY_DATA_CONNECTION_STATE_CHANGED");
-                if (VDBG) Log.d(LOG_TAG, "- state: " + intent.getStringExtra(PhoneConstants.STATE_KEY));
-                if (VDBG) Log.d(LOG_TAG, "- reason: "
-                                + intent.getStringExtra(PhoneConstants.STATE_CHANGE_REASON_KEY));
-
-                // The "data disconnected due to roaming" notification is shown
-                // if (a) you have the "data roaming" feature turned off, and
-                // (b) you just lost data connectivity because you're roaming.
-                boolean disconnectedDueToRoaming =
-                        !phone.getDataRoamingEnabled()
-                        && "DISCONNECTED".equals(intent.getStringExtra(PhoneConstants.STATE_KEY))
-                        && Phone.REASON_ROAMING_ON.equals(
-                            intent.getStringExtra(PhoneConstants.STATE_CHANGE_REASON_KEY));
-                mHandler.sendEmptyMessage(disconnectedDueToRoaming
-                                          ? EVENT_DATA_ROAMING_DISCONNECTED
-                                          : EVENT_DATA_ROAMING_OK);
-            } else if (action.equals(Intent.ACTION_HEADSET_PLUG)) {
-                if (VDBG) Log.d(LOG_TAG, "mReceiver: ACTION_HEADSET_PLUG");
-                if (VDBG) Log.d(LOG_TAG, "    state: " + intent.getIntExtra("state", 0));
-                if (VDBG) Log.d(LOG_TAG, "    name: " + intent.getStringExtra("name"));
-                mIsHeadsetPlugged = (intent.getIntExtra("state", 0) == 1);
-                mHandler.sendMessage(mHandler.obtainMessage(EVENT_WIRED_HEADSET_PLUG, 0));
-            } else if ((action.equals(TelephonyIntents.ACTION_SIM_STATE_CHANGED)) &&
-                    (mPUKEntryActivity != null)) {
-                // if an attempt to un-PUK-lock the device was made, while we're
-                // receiving this state change notification, notify the handler.
-                // NOTE: This is ONLY triggered if an attempt to un-PUK-lock has
-                // been attempted.
-                mHandler.sendMessage(mHandler.obtainMessage(EVENT_SIM_STATE_CHANGED,
-                        intent.getStringExtra(IccCardConstants.INTENT_KEY_ICC_STATE)));
-            } else if (action.equals(TelephonyIntents.ACTION_RADIO_TECHNOLOGY_CHANGED)) {
-                String newPhone = intent.getStringExtra(PhoneConstants.PHONE_NAME_KEY);
-                Log.d(LOG_TAG, "Radio technology switched. Now " + newPhone + " is active.");
-                initForNewRadioTechnology();
-            } else if (action.equals(TelephonyIntents.ACTION_SERVICE_STATE_CHANGED)) {
-                handleServiceStateChanged(intent);
-            } else if (action.equals(TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED)) {
-                if (TelephonyCapabilities.supportsEcm(phone)) {
-                    Log.d(LOG_TAG, "Emergency Callback Mode arrived in PhoneApp.");
-                    // Start Emergency Callback Mode service
-                    if (intent.getBooleanExtra("phoneinECMState", false)) {
-                        context.startService(new Intent(context,
-                                EmergencyCallbackModeService.class));
-                    }
-                } else {
-                    // It doesn't make sense to get ACTION_EMERGENCY_CALLBACK_MODE_CHANGED
-                    // on a device that doesn't support ECM in the first place.
-                    Log.e(LOG_TAG, "Got ACTION_EMERGENCY_CALLBACK_MODE_CHANGED, "
-                          + "but ECM isn't supported for phone: " + phone.getPhoneName());
-                }
-            } else if (action.equals(Intent.ACTION_DOCK_EVENT)) {
-                mDockState = intent.getIntExtra(Intent.EXTRA_DOCK_STATE,
-                        Intent.EXTRA_DOCK_STATE_UNDOCKED);
-                if (VDBG) Log.d(LOG_TAG, "ACTION_DOCK_EVENT -> mDockState = " + mDockState);
-                mHandler.sendMessage(mHandler.obtainMessage(EVENT_DOCK_STATE_CHANGED, 0));
-            } else if (action.equals(TtyIntent.TTY_PREFERRED_MODE_CHANGE_ACTION)) {
-                mPreferredTtyMode = intent.getIntExtra(TtyIntent.TTY_PREFFERED_MODE,
-                                                       Phone.TTY_MODE_OFF);
-                if (VDBG) Log.d(LOG_TAG, "mReceiver: TTY_PREFERRED_MODE_CHANGE_ACTION");
-                if (VDBG) Log.d(LOG_TAG, "    mode: " + mPreferredTtyMode);
-                mHandler.sendMessage(mHandler.obtainMessage(EVENT_TTY_PREFERRED_MODE_CHANGED, 0));
-            } else if (action.equals(AudioManager.RINGER_MODE_CHANGED_ACTION)) {
-                int ringerMode = intent.getIntExtra(AudioManager.EXTRA_RINGER_MODE,
-                        AudioManager.RINGER_MODE_NORMAL);
-                if (ringerMode == AudioManager.RINGER_MODE_SILENT) {
-                    notifier.silenceRinger();
-                }
-            }
-        }
-    }
-
-    /**
-     * Broadcast receiver for the ACTION_MEDIA_BUTTON broadcast intent.
-     *
-     * This functionality isn't lumped in with the other intents in
-     * PhoneAppBroadcastReceiver because we instantiate this as a totally
-     * separate BroadcastReceiver instance, since we need to manually
-     * adjust its IntentFilter's priority (to make sure we get these
-     * intents *before* the media player.)
-     */
-    private class MediaButtonBroadcastReceiver extends BroadcastReceiver {
-        @Override
-        public void onReceive(Context context, Intent intent) {
-            KeyEvent event = (KeyEvent) intent.getParcelableExtra(Intent.EXTRA_KEY_EVENT);
-            if (VDBG) Log.d(LOG_TAG,
-                           "MediaButtonBroadcastReceiver.onReceive()...  event = " + event);
-            if ((event != null)
-                && (event.getKeyCode() == KeyEvent.KEYCODE_HEADSETHOOK)) {
-                if (VDBG) Log.d(LOG_TAG, "MediaButtonBroadcastReceiver: HEADSETHOOK");
-                boolean consumed = PhoneUtils.handleHeadsetHook(phone, event);
-                if (VDBG) Log.d(LOG_TAG, "==> handleHeadsetHook(): consumed = " + consumed);
-                if (consumed) {
-                    // If a headset is attached and the press is consumed, also update
-                    // any UI items (such as an InCallScreen mute button) that may need to
-                    // be updated if their state changed.
-                    updateInCallScreen();  // Has no effect if the InCallScreen isn't visible
-                    abortBroadcast();
-                }
-            } else {
-                if (mCM.getState() != PhoneConstants.State.IDLE) {
-                    // If the phone is anything other than completely idle,
-                    // then we consume and ignore any media key events,
-                    // Otherwise it is too easy to accidentally start
-                    // playing music while a phone call is in progress.
-                    if (VDBG) Log.d(LOG_TAG, "MediaButtonBroadcastReceiver: consumed");
-                    abortBroadcast();
-                }
-            }
-        }
-    }
-
-    /**
-     * Accepts broadcast Intents which will be prepared by {@link NotificationMgr} and thus
-     * sent from framework's notification mechanism (which is outside Phone context).
-     * This should be visible from outside, but shouldn't be in "exported" state.
-     *
-     * TODO: If possible merge this into PhoneAppBroadcastReceiver.
-     */
-    public static class NotificationBroadcastReceiver extends BroadcastReceiver {
-        @Override
-        public void onReceive(Context context, Intent intent) {
-            String action = intent.getAction();
-            // TODO: use "if (VDBG)" here.
-            Log.d(LOG_TAG, "Broadcast from Notification: " + action);
-
-            if (action.equals(ACTION_HANG_UP_ONGOING_CALL)) {
-                PhoneUtils.hangup(PhoneApp.getInstance().mCM);
-            } else if (action.equals(ACTION_CALL_BACK_FROM_NOTIFICATION)) {
-                // Collapse the expanded notification and the notification item itself.
-                closeSystemDialogs(context);
-                clearMissedCallNotification(context);
-
-                Intent callIntent = new Intent(Intent.ACTION_CALL_PRIVILEGED, intent.getData());
-                callIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
-                        | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
-                context.startActivity(callIntent);
-            } else if (action.equals(ACTION_SEND_SMS_FROM_NOTIFICATION)) {
-                // Collapse the expanded notification and the notification item itself.
-                closeSystemDialogs(context);
-                clearMissedCallNotification(context);
-
-                Intent smsIntent = new Intent(Intent.ACTION_SENDTO, intent.getData());
-                smsIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-                context.startActivity(smsIntent);
-            } else {
-                Log.w(LOG_TAG, "Received hang-up request from notification,"
-                        + " but there's no call the system can hang up.");
-            }
-        }
-
-        private void closeSystemDialogs(Context context) {
-            Intent intent = new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
-            context.sendBroadcast(intent);
-        }
-
-        private void clearMissedCallNotification(Context context) {
-            Intent clearIntent = new Intent(context, ClearMissedCallsService.class);
-            clearIntent.setAction(ClearMissedCallsService.ACTION_CLEAR_MISSED_CALLS);
-            context.startService(clearIntent);
-        }
-    }
-
-    private void handleServiceStateChanged(Intent intent) {
-        /**
-         * This used to handle updating EriTextWidgetProvider this routine
-         * and and listening for ACTION_SERVICE_STATE_CHANGED intents could
-         * be removed. But leaving just in case it might be needed in the near
-         * future.
-         */
-
-        // If service just returned, start sending out the queued messages
-        ServiceState ss = ServiceState.newFromBundle(intent.getExtras());
-
-        if (ss != null) {
-            int state = ss.getState();
-            notificationMgr.updateNetworkSelection(state);
-        }
-    }
-
-    public boolean isOtaCallInActiveState() {
-        boolean otaCallActive = false;
-        if (mInCallScreen != null) {
-            otaCallActive = mInCallScreen.isOtaCallInActiveState();
-        }
-        if (VDBG) Log.d(LOG_TAG, "- isOtaCallInActiveState " + otaCallActive);
-        return otaCallActive;
-    }
-
-    public boolean isOtaCallInEndState() {
-        boolean otaCallEnded = false;
-        if (mInCallScreen != null) {
-            otaCallEnded = mInCallScreen.isOtaCallInEndState();
-        }
-        if (VDBG) Log.d(LOG_TAG, "- isOtaCallInEndState " + otaCallEnded);
-        return otaCallEnded;
-    }
-
-    // it is safe to call clearOtaState() even if the InCallScreen isn't active
-    public void clearOtaState() {
-        if (DBG) Log.d(LOG_TAG, "- clearOtaState ...");
-        if ((mInCallScreen != null)
-                && (otaUtils != null)) {
-            otaUtils.cleanOtaScreen(true);
-            if (DBG) Log.d(LOG_TAG, "  - clearOtaState clears OTA screen");
-        }
-    }
-
-    // it is safe to call dismissOtaDialogs() even if the InCallScreen isn't active
-    public void dismissOtaDialogs() {
-        if (DBG) Log.d(LOG_TAG, "- dismissOtaDialogs ...");
-        if ((mInCallScreen != null)
-                && (otaUtils != null)) {
-            otaUtils.dismissAllOtaDialogs();
-            if (DBG) Log.d(LOG_TAG, "  - dismissOtaDialogs clears OTA dialogs");
-        }
-    }
-
-    // it is safe to call clearInCallScreenMode() even if the InCallScreen isn't active
-    public void clearInCallScreenMode() {
-        if (DBG) Log.d(LOG_TAG, "- clearInCallScreenMode ...");
-        if (mInCallScreen != null) {
-            mInCallScreen.resetInCallScreenMode();
-        }
-    }
-
-    /**
-     * Force the in-call UI to refresh itself, if it's currently visible.
-     *
-     * This method can be used any time there's a state change anywhere in
-     * the phone app that needs to be reflected in the onscreen UI.
-     *
-     * Note that it's *not* necessary to manually refresh the in-call UI
-     * (via this method) for regular telephony state changes like
-     * DIALING -> ALERTING -> ACTIVE, since the InCallScreen already
-     * listens for those state changes itself.
-     *
-     * This method does *not* force the in-call UI to come up if it's not
-     * already visible.  To do that, use displayCallScreen().
-     */
-    /* package */ void updateInCallScreen() {
-        if (DBG) Log.d(LOG_TAG, "- updateInCallScreen()...");
-        if (mInCallScreen != null) {
-            // Post an updateScreen() request.  Note that the
-            // updateScreen() call will end up being a no-op if the
-            // InCallScreen isn't the foreground activity.
-            mInCallScreen.requestUpdateScreen();
-        }
-    }
-
-    private void handleQueryTTYModeResponse(Message msg) {
-        AsyncResult ar = (AsyncResult) msg.obj;
-        if (ar.exception != null) {
-            if (DBG) Log.d(LOG_TAG, "handleQueryTTYModeResponse: Error getting TTY state.");
-        } else {
-            if (DBG) Log.d(LOG_TAG,
-                           "handleQueryTTYModeResponse: TTY enable state successfully queried.");
-
-            int ttymode = ((int[]) ar.result)[0];
-            if (DBG) Log.d(LOG_TAG, "handleQueryTTYModeResponse:ttymode=" + ttymode);
-
-            Intent ttyModeChanged = new Intent(TtyIntent.TTY_ENABLED_CHANGE_ACTION);
-            ttyModeChanged.putExtra("ttyEnabled", ttymode != Phone.TTY_MODE_OFF);
-            sendBroadcast(ttyModeChanged);
-
-            String audioTtyMode;
-            switch (ttymode) {
-            case Phone.TTY_MODE_FULL:
-                audioTtyMode = "tty_full";
-                break;
-            case Phone.TTY_MODE_VCO:
-                audioTtyMode = "tty_vco";
-                break;
-            case Phone.TTY_MODE_HCO:
-                audioTtyMode = "tty_hco";
-                break;
-            case Phone.TTY_MODE_OFF:
-            default:
-                audioTtyMode = "tty_off";
-                break;
-            }
-            AudioManager audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
-            audioManager.setParameters("tty_mode="+audioTtyMode);
-        }
-    }
-
-    private void handleSetTTYModeResponse(Message msg) {
-        AsyncResult ar = (AsyncResult) msg.obj;
-
-        if (ar.exception != null) {
-            if (DBG) Log.d (LOG_TAG,
-                    "handleSetTTYModeResponse: Error setting TTY mode, ar.exception"
-                    + ar.exception);
-        }
-        phone.queryTTYMode(mHandler.obtainMessage(EVENT_TTY_MODE_GET));
-    }
-
-    /* package */ void clearUserActivityTimeout() {
-        try {
-            mPowerManagerService.clearUserActivityTimeout(SystemClock.uptimeMillis(),
-                    10*1000 /* 10 sec */);
-        } catch (RemoteException ex) {
-            // System process is dead.
-        }
-    }
-
-    /**
-     * "Call origin" may be used by Contacts app to specify where the phone call comes from.
-     * Currently, the only permitted value for this extra is {@link #ALLOWED_EXTRA_CALL_ORIGIN}.
-     * Any other value will be ignored, to make sure that malicious apps can't trick the in-call
-     * UI into launching some random other app after a call ends.
-     *
-     * TODO: make this more generic. Note that we should let the "origin" specify its package
-     * while we are now assuming it is "com.android.contacts"
-     */
-    public static final String EXTRA_CALL_ORIGIN = "com.android.phone.CALL_ORIGIN";
-    private static final String DEFAULT_CALL_ORIGIN_PACKAGE = "com.android.contacts";
-    private static final String ALLOWED_EXTRA_CALL_ORIGIN =
-            "com.android.contacts.activities.DialtactsActivity";
-    /**
-     * Used to determine if the preserved call origin is fresh enough.
-     */
-    private static final long CALL_ORIGIN_EXPIRATION_MILLIS = 30 * 1000;
-
-    public void setLatestActiveCallOrigin(String callOrigin) {
-        inCallUiState.latestActiveCallOrigin = callOrigin;
-        if (callOrigin != null) {
-            inCallUiState.latestActiveCallOriginTimeStamp = SystemClock.elapsedRealtime();
-        } else {
-            inCallUiState.latestActiveCallOriginTimeStamp = 0;
-        }
-    }
-
-    /**
-     * Reset call origin depending on its timestamp.
-     *
-     * See if the current call origin preserved by the app is fresh enough or not. If it is,
-     * previous call origin will be used as is. If not, call origin will be reset.
-     *
-     * This will be effective especially for 3rd party apps which want to bypass phone calls with
-     * their own telephone lines. In that case Phone app may finish the phone call once and make
-     * another for the external apps, which will drop call origin information in Intent.
-     * Even in that case we are sure the second phone call should be initiated just after the first
-     * phone call, so here we restore it from the previous information iff the second call is done
-     * fairly soon.
-     */
-    public void resetLatestActiveCallOrigin() {
-        final long callOriginTimestamp = inCallUiState.latestActiveCallOriginTimeStamp;
-        final long currentTimestamp = SystemClock.elapsedRealtime();
-        if (VDBG) {
-            Log.d(LOG_TAG, "currentTimeMillis: " + currentTimestamp
-                    + ", saved timestamp for call origin: " + callOriginTimestamp);
-        }
-        if (inCallUiState.latestActiveCallOriginTimeStamp > 0
-                && (currentTimestamp - callOriginTimestamp < CALL_ORIGIN_EXPIRATION_MILLIS)) {
-            if (VDBG) {
-                Log.d(LOG_TAG, "Resume previous call origin (" +
-                        inCallUiState.latestActiveCallOrigin + ")");
-            }
-            // Do nothing toward call origin itself but update the timestamp just in case.
-            inCallUiState.latestActiveCallOriginTimeStamp = currentTimestamp;
-        } else {
-            if (VDBG) Log.d(LOG_TAG, "Drop previous call origin and set the current one to null");
-            setLatestActiveCallOrigin(null);
-        }
-    }
-
-    /**
-     * @return Intent which will be used when in-call UI is shown and the phone call is hang up.
-     * By default CallLog screen will be introduced, but the destination may change depending on
-     * its latest call origin state.
-     */
-    public Intent createPhoneEndIntentUsingCallOrigin() {
-        if (TextUtils.equals(inCallUiState.latestActiveCallOrigin, ALLOWED_EXTRA_CALL_ORIGIN)) {
-            if (VDBG) Log.d(LOG_TAG, "Valid latestActiveCallOrigin("
-                    + inCallUiState.latestActiveCallOrigin + ") was found. "
-                    + "Go back to the previous screen.");
-            // Right now we just launch the Activity which launched in-call UI. Note that we're
-            // assuming the origin is from "com.android.contacts", which may be incorrect in the
-            // future.
-            final Intent intent = new Intent();
-            intent.setClassName(DEFAULT_CALL_ORIGIN_PACKAGE, inCallUiState.latestActiveCallOrigin);
-            return intent;
-        } else {
-            if (VDBG) Log.d(LOG_TAG, "Current latestActiveCallOrigin ("
-                    + inCallUiState.latestActiveCallOrigin + ") is not valid. "
-                    + "Just use CallLog as a default destination.");
-            return PhoneApp.createCallLogIntent();
-        }
-    }
 }
diff --git a/src/com/android/phone/PhoneGlobals.java b/src/com/android/phone/PhoneGlobals.java
new file mode 100644
index 0000000..acfdd7e
--- /dev/null
+++ b/src/com/android/phone/PhoneGlobals.java
@@ -0,0 +1,1850 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.phone;
+
+import android.app.Activity;
+import android.app.KeyguardManager;
+import android.app.PendingIntent;
+import android.app.ProgressDialog;
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothHeadset;
+import android.bluetooth.BluetoothProfile;
+import android.bluetooth.IBluetoothHeadsetPhone;
+import android.content.ActivityNotFoundException;
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.ContextWrapper;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.ServiceConnection;
+import android.content.res.Configuration;
+import android.media.AudioManager;
+import android.net.Uri;
+import android.os.AsyncResult;
+import android.os.Binder;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.IPowerManager;
+import android.os.Message;
+import android.os.PowerManager;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.os.SystemClock;
+import android.os.SystemProperties;
+import android.os.UpdateLock;
+import android.os.UserHandle;
+import android.preference.PreferenceManager;
+import android.provider.Settings.System;
+import android.telephony.ServiceState;
+import android.text.TextUtils;
+import android.util.Log;
+import android.util.Slog;
+import android.view.KeyEvent;
+
+import com.android.internal.telephony.Call;
+import com.android.internal.telephony.CallManager;
+import com.android.internal.telephony.IccCard;
+import com.android.internal.telephony.IccCardConstants;
+import com.android.internal.telephony.MmiCode;
+import com.android.internal.telephony.Phone;
+import com.android.internal.telephony.PhoneConstants;
+import com.android.internal.telephony.PhoneFactory;
+import com.android.internal.telephony.TelephonyCapabilities;
+import com.android.internal.telephony.TelephonyIntents;
+import com.android.internal.telephony.cdma.TtyIntent;
+import com.android.phone.OtaUtils.CdmaOtaScreenState;
+import com.android.server.sip.SipService;
+
+/**
+ * Global state for the telephony subsystem when running in the primary
+ * phone process.
+ */
+public class PhoneGlobals extends ContextWrapper
+        implements AccelerometerListener.OrientationListener {
+    /* package */ static final String LOG_TAG = "PhoneApp";
+
+    /**
+     * Phone app-wide debug level:
+     *   0 - no debug logging
+     *   1 - normal debug logging if ro.debuggable is set (which is true in
+     *       "eng" and "userdebug" builds but not "user" builds)
+     *   2 - ultra-verbose debug logging
+     *
+     * Most individual classes in the phone app have a local DBG constant,
+     * typically set to
+     *   (PhoneApp.DBG_LEVEL >= 1) && (SystemProperties.getInt("ro.debuggable", 0) == 1)
+     * or else
+     *   (PhoneApp.DBG_LEVEL >= 2)
+     * depending on the desired verbosity.
+     *
+     * ***** DO NOT SUBMIT WITH DBG_LEVEL > 0 *************
+     */
+    /* package */ static final int DBG_LEVEL = 0;
+
+    private static final boolean DBG =
+            (PhoneGlobals.DBG_LEVEL >= 1) && (SystemProperties.getInt("ro.debuggable", 0) == 1);
+    private static final boolean VDBG = (PhoneGlobals.DBG_LEVEL >= 2);
+
+    // Message codes; see mHandler below.
+    private static final int EVENT_SIM_NETWORK_LOCKED = 3;
+    private static final int EVENT_WIRED_HEADSET_PLUG = 7;
+    private static final int EVENT_SIM_STATE_CHANGED = 8;
+    private static final int EVENT_UPDATE_INCALL_NOTIFICATION = 9;
+    private static final int EVENT_DATA_ROAMING_DISCONNECTED = 10;
+    private static final int EVENT_DATA_ROAMING_OK = 11;
+    private static final int EVENT_UNSOL_CDMA_INFO_RECORD = 12;
+    private static final int EVENT_DOCK_STATE_CHANGED = 13;
+    private static final int EVENT_TTY_PREFERRED_MODE_CHANGED = 14;
+    private static final int EVENT_TTY_MODE_GET = 15;
+    private static final int EVENT_TTY_MODE_SET = 16;
+    private static final int EVENT_START_SIP_SERVICE = 17;
+
+    // The MMI codes are also used by the InCallScreen.
+    public static final int MMI_INITIATE = 51;
+    public static final int MMI_COMPLETE = 52;
+    public static final int MMI_CANCEL = 53;
+    // Don't use message codes larger than 99 here; those are reserved for
+    // the individual Activities of the Phone UI.
+
+    /**
+     * Allowable values for the wake lock code.
+     *   SLEEP means the device can be put to sleep.
+     *   PARTIAL means wake the processor, but we display can be kept off.
+     *   FULL means wake both the processor and the display.
+     */
+    public enum WakeState {
+        SLEEP,
+        PARTIAL,
+        FULL
+    }
+
+    /**
+     * Intent Action used for hanging up the current call from Notification bar. This will
+     * choose first ringing call, first active call, or first background call (typically in
+     * HOLDING state).
+     */
+    public static final String ACTION_HANG_UP_ONGOING_CALL =
+            "com.android.phone.ACTION_HANG_UP_ONGOING_CALL";
+
+    /**
+     * Intent Action used for making a phone call from Notification bar.
+     * This is for missed call notifications.
+     */
+    public static final String ACTION_CALL_BACK_FROM_NOTIFICATION =
+            "com.android.phone.ACTION_CALL_BACK_FROM_NOTIFICATION";
+
+    /**
+     * Intent Action used for sending a SMS from notification bar.
+     * This is for missed call notifications.
+     */
+    public static final String ACTION_SEND_SMS_FROM_NOTIFICATION =
+            "com.android.phone.ACTION_SEND_SMS_FROM_NOTIFICATION";
+
+    private static PhoneGlobals sMe;
+
+    // A few important fields we expose to the rest of the package
+    // directly (rather than thru set/get methods) for efficiency.
+    Phone phone;
+    CallController callController;
+    InCallUiState inCallUiState;
+    CallerInfoCache callerInfoCache;
+    CallNotifier notifier;
+    NotificationMgr notificationMgr;
+    Ringer ringer;
+    IBluetoothHeadsetPhone mBluetoothPhone;
+    PhoneInterfaceManager phoneMgr;
+    CallManager mCM;
+    int mBluetoothHeadsetState = BluetoothProfile.STATE_DISCONNECTED;
+    int mBluetoothHeadsetAudioState = BluetoothHeadset.STATE_AUDIO_DISCONNECTED;
+    boolean mShowBluetoothIndication = false;
+    static int mDockState = Intent.EXTRA_DOCK_STATE_UNDOCKED;
+    static boolean sVoiceCapable = true;
+
+    // Internal PhoneApp Call state tracker
+    CdmaPhoneCallState cdmaPhoneCallState;
+
+    // The InCallScreen instance (or null if the InCallScreen hasn't been
+    // created yet.)
+    private InCallScreen mInCallScreen;
+
+    // The currently-active PUK entry activity and progress dialog.
+    // Normally, these are the Emergency Dialer and the subsequent
+    // progress dialog.  null if there is are no such objects in
+    // the foreground.
+    private Activity mPUKEntryActivity;
+    private ProgressDialog mPUKEntryProgressDialog;
+
+    private boolean mIsSimPinEnabled;
+    private String mCachedSimPin;
+
+    // True if a wired headset is currently plugged in, based on the state
+    // from the latest Intent.ACTION_HEADSET_PLUG broadcast we received in
+    // mReceiver.onReceive().
+    private boolean mIsHeadsetPlugged;
+
+    // True if the keyboard is currently *not* hidden
+    // Gets updated whenever there is a Configuration change
+    private boolean mIsHardKeyboardOpen;
+
+    // True if we are beginning a call, but the phone state has not changed yet
+    private boolean mBeginningCall;
+
+    // Last phone state seen by updatePhoneState()
+    private PhoneConstants.State mLastPhoneState = PhoneConstants.State.IDLE;
+
+    private WakeState mWakeState = WakeState.SLEEP;
+
+    private PowerManager mPowerManager;
+    private IPowerManager mPowerManagerService;
+    private PowerManager.WakeLock mWakeLock;
+    private PowerManager.WakeLock mPartialWakeLock;
+    private PowerManager.WakeLock mProximityWakeLock;
+    private KeyguardManager mKeyguardManager;
+    private AccelerometerListener mAccelerometerListener;
+    private int mOrientation = AccelerometerListener.ORIENTATION_UNKNOWN;
+
+    private UpdateLock mUpdateLock;
+
+    // Broadcast receiver for various intent broadcasts (see onCreate())
+    private final BroadcastReceiver mReceiver = new PhoneAppBroadcastReceiver();
+
+    // Broadcast receiver purely for ACTION_MEDIA_BUTTON broadcasts
+    private final BroadcastReceiver mMediaButtonReceiver = new MediaButtonBroadcastReceiver();
+
+    /** boolean indicating restoring mute state on InCallScreen.onResume() */
+    private boolean mShouldRestoreMuteOnInCallResume;
+
+    /**
+     * The singleton OtaUtils instance used for OTASP calls.
+     *
+     * The OtaUtils instance is created lazily the first time we need to
+     * make an OTASP call, regardless of whether it's an interactive or
+     * non-interactive OTASP call.
+     */
+    public OtaUtils otaUtils;
+
+    // Following are the CDMA OTA information Objects used during OTA Call.
+    // cdmaOtaProvisionData object store static OTA information that needs
+    // to be maintained even during Slider open/close scenarios.
+    // cdmaOtaConfigData object stores configuration info to control visiblity
+    // of each OTA Screens.
+    // cdmaOtaScreenState object store OTA Screen State information.
+    public OtaUtils.CdmaOtaProvisionData cdmaOtaProvisionData;
+    public OtaUtils.CdmaOtaConfigData cdmaOtaConfigData;
+    public OtaUtils.CdmaOtaScreenState cdmaOtaScreenState;
+    public OtaUtils.CdmaOtaInCallScreenUiState cdmaOtaInCallScreenUiState;
+
+    // TTY feature enabled on this platform
+    private boolean mTtyEnabled;
+    // Current TTY operating mode selected by user
+    private int mPreferredTtyMode = Phone.TTY_MODE_OFF;
+
+    /**
+     * Set the restore mute state flag. Used when we are setting the mute state
+     * OUTSIDE of user interaction {@link PhoneUtils#startNewCall(Phone)}
+     */
+    /*package*/void setRestoreMuteOnInCallResume (boolean mode) {
+        mShouldRestoreMuteOnInCallResume = mode;
+    }
+
+    /**
+     * Get the restore mute state flag.
+     * This is used by the InCallScreen {@link InCallScreen#onResume()} to figure
+     * out if we need to restore the mute state for the current active call.
+     */
+    /*package*/boolean getRestoreMuteOnInCallResume () {
+        return mShouldRestoreMuteOnInCallResume;
+    }
+
+    Handler mHandler = new Handler() {
+        @Override
+        public void handleMessage(Message msg) {
+            PhoneConstants.State phoneState;
+            switch (msg.what) {
+                // Starts the SIP service. It's a no-op if SIP API is not supported
+                // on the deivce.
+                // TODO: Having the phone process host the SIP service is only
+                // temporary. Will move it to a persistent communication process
+                // later.
+                case EVENT_START_SIP_SERVICE:
+                    SipService.start(getApplicationContext());
+                    break;
+
+                // TODO: This event should be handled by the lock screen, just
+                // like the "SIM missing" and "Sim locked" cases (bug 1804111).
+                case EVENT_SIM_NETWORK_LOCKED:
+                    if (getResources().getBoolean(R.bool.ignore_sim_network_locked_events)) {
+                        // Some products don't have the concept of a "SIM network lock"
+                        Log.i(LOG_TAG, "Ignoring EVENT_SIM_NETWORK_LOCKED event; "
+                              + "not showing 'SIM network unlock' PIN entry screen");
+                    } else {
+                        // Normal case: show the "SIM network unlock" PIN entry screen.
+                        // The user won't be able to do anything else until
+                        // they enter a valid SIM network PIN.
+                        Log.i(LOG_TAG, "show sim depersonal panel");
+                        IccNetworkDepersonalizationPanel ndpPanel =
+                                new IccNetworkDepersonalizationPanel(PhoneGlobals.getInstance());
+                        ndpPanel.show();
+                    }
+                    break;
+
+                case EVENT_UPDATE_INCALL_NOTIFICATION:
+                    // Tell the NotificationMgr to update the "ongoing
+                    // call" icon in the status bar, if necessary.
+                    // Currently, this is triggered by a bluetooth headset
+                    // state change (since the status bar icon needs to
+                    // turn blue when bluetooth is active.)
+                    if (DBG) Log.d (LOG_TAG, "- updating in-call notification from handler...");
+                    notificationMgr.updateInCallNotification();
+                    break;
+
+                case EVENT_DATA_ROAMING_DISCONNECTED:
+                    notificationMgr.showDataDisconnectedRoaming();
+                    break;
+
+                case EVENT_DATA_ROAMING_OK:
+                    notificationMgr.hideDataDisconnectedRoaming();
+                    break;
+
+                case MMI_COMPLETE:
+                    onMMIComplete((AsyncResult) msg.obj);
+                    break;
+
+                case MMI_CANCEL:
+                    PhoneUtils.cancelMmiCode(phone);
+                    break;
+
+                case EVENT_WIRED_HEADSET_PLUG:
+                    // Since the presence of a wired headset or bluetooth affects the
+                    // speakerphone, update the "speaker" state.  We ONLY want to do
+                    // this on the wired headset connect / disconnect events for now
+                    // though, so we're only triggering on EVENT_WIRED_HEADSET_PLUG.
+
+                    phoneState = mCM.getState();
+                    // Do not change speaker state if phone is not off hook
+                    if (phoneState == PhoneConstants.State.OFFHOOK && !isBluetoothHeadsetAudioOn()) {
+                        if (!isHeadsetPlugged()) {
+                            // if the state is "not connected", restore the speaker state.
+                            PhoneUtils.restoreSpeakerMode(getApplicationContext());
+                        } else {
+                            // if the state is "connected", force the speaker off without
+                            // storing the state.
+                            PhoneUtils.turnOnSpeaker(getApplicationContext(), false, false);
+                        }
+                    }
+                    // Update the Proximity sensor based on headset state
+                    updateProximitySensorMode(phoneState);
+
+                    // Force TTY state update according to new headset state
+                    if (mTtyEnabled) {
+                        sendMessage(obtainMessage(EVENT_TTY_PREFERRED_MODE_CHANGED, 0));
+                    }
+                    break;
+
+                case EVENT_SIM_STATE_CHANGED:
+                    // Marks the event where the SIM goes into ready state.
+                    // Right now, this is only used for the PUK-unlocking
+                    // process.
+                    if (msg.obj.equals(IccCardConstants.INTENT_VALUE_ICC_READY)) {
+                        // when the right event is triggered and there
+                        // are UI objects in the foreground, we close
+                        // them to display the lock panel.
+                        if (mPUKEntryActivity != null) {
+                            mPUKEntryActivity.finish();
+                            mPUKEntryActivity = null;
+                        }
+                        if (mPUKEntryProgressDialog != null) {
+                            mPUKEntryProgressDialog.dismiss();
+                            mPUKEntryProgressDialog = null;
+                        }
+                    }
+                    break;
+
+                case EVENT_UNSOL_CDMA_INFO_RECORD:
+                    //TODO: handle message here;
+                    break;
+
+                case EVENT_DOCK_STATE_CHANGED:
+                    // If the phone is docked/undocked during a call, and no wired or BT headset
+                    // is connected: turn on/off the speaker accordingly.
+                    boolean inDockMode = false;
+                    if (mDockState != Intent.EXTRA_DOCK_STATE_UNDOCKED) {
+                        inDockMode = true;
+                    }
+                    if (VDBG) Log.d(LOG_TAG, "received EVENT_DOCK_STATE_CHANGED. Phone inDock = "
+                            + inDockMode);
+
+                    phoneState = mCM.getState();
+                    if (phoneState == PhoneConstants.State.OFFHOOK &&
+                        !isHeadsetPlugged() && !isBluetoothHeadsetAudioOn()) {
+                        PhoneUtils.turnOnSpeaker(getApplicationContext(), inDockMode, true);
+                        updateInCallScreen();  // Has no effect if the InCallScreen isn't visible
+                    }
+                    break;
+
+                case EVENT_TTY_PREFERRED_MODE_CHANGED:
+                    // TTY mode is only applied if a headset is connected
+                    int ttyMode;
+                    if (isHeadsetPlugged()) {
+                        ttyMode = mPreferredTtyMode;
+                    } else {
+                        ttyMode = Phone.TTY_MODE_OFF;
+                    }
+                    phone.setTTYMode(ttyMode, mHandler.obtainMessage(EVENT_TTY_MODE_SET));
+                    break;
+
+                case EVENT_TTY_MODE_GET:
+                    handleQueryTTYModeResponse(msg);
+                    break;
+
+                case EVENT_TTY_MODE_SET:
+                    handleSetTTYModeResponse(msg);
+                    break;
+            }
+        }
+    };
+
+    public PhoneGlobals(Context context) {
+        super(context);
+        sMe = this;
+    }
+
+    public void onCreate() {
+        if (VDBG) Log.v(LOG_TAG, "onCreate()...");
+
+        ContentResolver resolver = getContentResolver();
+
+        // Cache the "voice capable" flag.
+        // This flag currently comes from a resource (which is
+        // overrideable on a per-product basis):
+        sVoiceCapable =
+                getResources().getBoolean(com.android.internal.R.bool.config_voice_capable);
+        // ...but this might eventually become a PackageManager "system
+        // feature" instead, in which case we'd do something like:
+        // sVoiceCapable =
+        //   getPackageManager().hasSystemFeature(PackageManager.FEATURE_TELEPHONY_VOICE_CALLS);
+
+        if (phone == null) {
+            // Initialize the telephony framework
+            PhoneFactory.makeDefaultPhones(this);
+
+            // Get the default phone
+            phone = PhoneFactory.getDefaultPhone();
+
+            // Start TelephonyDebugService After the default phone is created.
+            Intent intent = new Intent(this, TelephonyDebugService.class);
+            startService(intent);
+
+            mCM = CallManager.getInstance();
+            mCM.registerPhone(phone);
+
+            // Create the NotificationMgr singleton, which is used to display
+            // status bar icons and control other status bar behavior.
+            notificationMgr = NotificationMgr.init(this);
+
+            phoneMgr = PhoneInterfaceManager.init(this, phone);
+
+            mHandler.sendEmptyMessage(EVENT_START_SIP_SERVICE);
+
+            int phoneType = phone.getPhoneType();
+
+            if (phoneType == PhoneConstants.PHONE_TYPE_CDMA) {
+                // Create an instance of CdmaPhoneCallState and initialize it to IDLE
+                cdmaPhoneCallState = new CdmaPhoneCallState();
+                cdmaPhoneCallState.CdmaPhoneCallStateInit();
+            }
+
+            if (BluetoothAdapter.getDefaultAdapter() != null) {
+                // Start BluetoothPhoneService even if device is not voice capable.
+                // The device can still support VOIP.
+                startService(new Intent(this, BluetoothPhoneService.class));
+                bindService(new Intent(this, BluetoothPhoneService.class),
+                            mBluetoothPhoneConnection, 0);
+            } else {
+                // Device is not bluetooth capable
+                mBluetoothPhone = null;
+            }
+
+            ringer = Ringer.init(this);
+
+            // before registering for phone state changes
+            mPowerManager = (PowerManager) getSystemService(Context.POWER_SERVICE);
+            mWakeLock = mPowerManager.newWakeLock(PowerManager.FULL_WAKE_LOCK, LOG_TAG);
+            // lock used to keep the processor awake, when we don't care for the display.
+            mPartialWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK
+                    | PowerManager.ON_AFTER_RELEASE, LOG_TAG);
+            // Wake lock used to control proximity sensor behavior.
+            if (mPowerManager.isWakeLockLevelSupported(
+                    PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK)) {
+                mProximityWakeLock = mPowerManager.newWakeLock(
+                        PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK, LOG_TAG);
+            }
+            if (DBG) Log.d(LOG_TAG, "onCreate: mProximityWakeLock: " + mProximityWakeLock);
+
+            // create mAccelerometerListener only if we are using the proximity sensor
+            if (proximitySensorModeEnabled()) {
+                mAccelerometerListener = new AccelerometerListener(this, this);
+            }
+
+            mKeyguardManager = (KeyguardManager) getSystemService(Context.KEYGUARD_SERVICE);
+
+            // get a handle to the service so that we can use it later when we
+            // want to set the poke lock.
+            mPowerManagerService = IPowerManager.Stub.asInterface(
+                    ServiceManager.getService("power"));
+
+            // Get UpdateLock to suppress system-update related events (e.g. dialog show-up)
+            // during phone calls.
+            mUpdateLock = new UpdateLock("phone");
+
+            if (DBG) Log.d(LOG_TAG, "onCreate: mUpdateLock: " + mUpdateLock);
+
+            // Create the CallController singleton, which is the interface
+            // to the telephony layer for user-initiated telephony functionality
+            // (like making outgoing calls.)
+            callController = CallController.init(this);
+            // ...and also the InCallUiState instance, used by the CallController to
+            // keep track of some "persistent state" of the in-call UI.
+            inCallUiState = InCallUiState.init(this);
+
+            // Create the CallerInfoCache singleton, which remembers custom ring tone and
+            // send-to-voicemail settings.
+            //
+            // The asynchronous caching will start just after this call.
+            callerInfoCache = CallerInfoCache.init(this);
+
+            // Create the CallNotifer singleton, which handles
+            // asynchronous events from the telephony layer (like
+            // launching the incoming-call UI when an incoming call comes
+            // in.)
+            notifier = CallNotifier.init(this, phone, ringer, new CallLogAsync());
+
+            // register for ICC status
+            IccCard sim = phone.getIccCard();
+            if (sim != null) {
+                if (VDBG) Log.v(LOG_TAG, "register for ICC status");
+                sim.registerForNetworkLocked(mHandler, EVENT_SIM_NETWORK_LOCKED, null);
+            }
+
+            // register for MMI/USSD
+            mCM.registerForMmiComplete(mHandler, MMI_COMPLETE, null);
+
+            // register connection tracking to PhoneUtils
+            PhoneUtils.initializeConnectionHandler(mCM);
+
+            // Read platform settings for TTY feature
+            mTtyEnabled = getResources().getBoolean(R.bool.tty_enabled);
+
+            // Register for misc other intent broadcasts.
+            IntentFilter intentFilter =
+                    new IntentFilter(Intent.ACTION_AIRPLANE_MODE_CHANGED);
+            intentFilter.addAction(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED);
+            intentFilter.addAction(BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED);
+            intentFilter.addAction(TelephonyIntents.ACTION_ANY_DATA_CONNECTION_STATE_CHANGED);
+            intentFilter.addAction(Intent.ACTION_HEADSET_PLUG);
+            intentFilter.addAction(Intent.ACTION_DOCK_EVENT);
+            intentFilter.addAction(TelephonyIntents.ACTION_SIM_STATE_CHANGED);
+            intentFilter.addAction(TelephonyIntents.ACTION_RADIO_TECHNOLOGY_CHANGED);
+            intentFilter.addAction(TelephonyIntents.ACTION_SERVICE_STATE_CHANGED);
+            intentFilter.addAction(TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED);
+            if (mTtyEnabled) {
+                intentFilter.addAction(TtyIntent.TTY_PREFERRED_MODE_CHANGE_ACTION);
+            }
+            intentFilter.addAction(AudioManager.RINGER_MODE_CHANGED_ACTION);
+            registerReceiver(mReceiver, intentFilter);
+
+            // Use a separate receiver for ACTION_MEDIA_BUTTON broadcasts,
+            // since we need to manually adjust its priority (to make sure
+            // we get these intents *before* the media player.)
+            IntentFilter mediaButtonIntentFilter =
+                    new IntentFilter(Intent.ACTION_MEDIA_BUTTON);
+            // TODO verify the independent priority doesn't need to be handled thanks to the
+            //  private intent handler registration
+            // Make sure we're higher priority than the media player's
+            // MediaButtonIntentReceiver (which currently has the default
+            // priority of zero; see apps/Music/AndroidManifest.xml.)
+            mediaButtonIntentFilter.setPriority(1);
+            //
+            registerReceiver(mMediaButtonReceiver, mediaButtonIntentFilter);
+            // register the component so it gets priority for calls
+            AudioManager am = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
+            am.registerMediaButtonEventReceiverForCalls(new ComponentName(this.getPackageName(),
+                    MediaButtonBroadcastReceiver.class.getName()));
+
+            //set the default values for the preferences in the phone.
+            PreferenceManager.setDefaultValues(this, R.xml.network_setting, false);
+
+            PreferenceManager.setDefaultValues(this, R.xml.call_feature_setting, false);
+
+            // Make sure the audio mode (along with some
+            // audio-mode-related state of our own) is initialized
+            // correctly, given the current state of the phone.
+            PhoneUtils.setAudioMode(mCM);
+        }
+
+        if (TelephonyCapabilities.supportsOtasp(phone)) {
+            cdmaOtaProvisionData = new OtaUtils.CdmaOtaProvisionData();
+            cdmaOtaConfigData = new OtaUtils.CdmaOtaConfigData();
+            cdmaOtaScreenState = new OtaUtils.CdmaOtaScreenState();
+            cdmaOtaInCallScreenUiState = new OtaUtils.CdmaOtaInCallScreenUiState();
+        }
+
+        // XXX pre-load the SimProvider so that it's ready
+        resolver.getType(Uri.parse("content://icc/adn"));
+
+        // start with the default value to set the mute state.
+        mShouldRestoreMuteOnInCallResume = false;
+
+        // TODO: Register for Cdma Information Records
+        // phone.registerCdmaInformationRecord(mHandler, EVENT_UNSOL_CDMA_INFO_RECORD, null);
+
+        // Read TTY settings and store it into BP NV.
+        // AP owns (i.e. stores) the TTY setting in AP settings database and pushes the setting
+        // to BP at power up (BP does not need to make the TTY setting persistent storage).
+        // This way, there is a single owner (i.e AP) for the TTY setting in the phone.
+        if (mTtyEnabled) {
+            mPreferredTtyMode = android.provider.Settings.Secure.getInt(
+                    phone.getContext().getContentResolver(),
+                    android.provider.Settings.Secure.PREFERRED_TTY_MODE,
+                    Phone.TTY_MODE_OFF);
+            mHandler.sendMessage(mHandler.obtainMessage(EVENT_TTY_PREFERRED_MODE_CHANGED, 0));
+        }
+        // Read HAC settings and configure audio hardware
+        if (getResources().getBoolean(R.bool.hac_enabled)) {
+            int hac = android.provider.Settings.System.getInt(phone.getContext().getContentResolver(),
+                                                              android.provider.Settings.System.HEARING_AID,
+                                                              0);
+            AudioManager audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
+            audioManager.setParameter(CallFeaturesSetting.HAC_KEY, hac != 0 ?
+                                      CallFeaturesSetting.HAC_VAL_ON :
+                                      CallFeaturesSetting.HAC_VAL_OFF);
+        }
+   }
+
+    public void onConfigurationChanged(Configuration newConfig) {
+        if (newConfig.hardKeyboardHidden == Configuration.HARDKEYBOARDHIDDEN_NO) {
+            mIsHardKeyboardOpen = true;
+        } else {
+            mIsHardKeyboardOpen = false;
+        }
+
+        // Update the Proximity sensor based on keyboard state
+        updateProximitySensorMode(mCM.getState());
+    }
+
+    /**
+     * Returns the singleton instance of the PhoneApp.
+     */
+    static PhoneGlobals getInstance() {
+        if (sMe == null) {
+            throw new IllegalStateException("No PhoneGlobals here!");
+        }
+        return sMe;
+    }
+
+    /**
+     * Returns the singleton instance of the PhoneApp if running as the
+     * primary user, otherwise null.
+     */
+    static PhoneGlobals getInstanceIfPrimary() {
+        return sMe;
+    }
+
+    /**
+     * Returns the Phone associated with this instance
+     */
+    static Phone getPhone() {
+        return getInstance().phone;
+    }
+
+    Ringer getRinger() {
+        return ringer;
+    }
+
+    IBluetoothHeadsetPhone getBluetoothPhoneService() {
+        return mBluetoothPhone;
+    }
+
+    boolean isBluetoothHeadsetAudioOn() {
+        return (mBluetoothHeadsetAudioState != BluetoothHeadset.STATE_AUDIO_DISCONNECTED);
+    }
+
+    /**
+     * Returns an Intent that can be used to go to the "Call log"
+     * UI (aka CallLogActivity) in the Contacts app.
+     *
+     * Watch out: there's no guarantee that the system has any activity to
+     * handle this intent.  (In particular there may be no "Call log" at
+     * all on on non-voice-capable devices.)
+     */
+    /* package */ static Intent createCallLogIntent() {
+        Intent intent = new Intent(Intent.ACTION_VIEW, null);
+        intent.setType("vnd.android.cursor.dir/calls");
+        return intent;
+    }
+
+    /**
+     * Return an Intent that can be used to bring up the in-call screen.
+     *
+     * This intent can only be used from within the Phone app, since the
+     * InCallScreen is not exported from our AndroidManifest.
+     */
+    /* package */ static Intent createInCallIntent() {
+        Intent intent = new Intent(Intent.ACTION_MAIN, null);
+        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
+                | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
+                | Intent.FLAG_ACTIVITY_NO_USER_ACTION);
+        intent.setClassName("com.android.phone", getCallScreenClassName());
+        return intent;
+    }
+
+    /**
+     * Variation of createInCallIntent() that also specifies whether the
+     * DTMF dialpad should be initially visible when the InCallScreen
+     * comes up.
+     */
+    /* package */ static Intent createInCallIntent(boolean showDialpad) {
+        Intent intent = createInCallIntent();
+        intent.putExtra(InCallScreen.SHOW_DIALPAD_EXTRA, showDialpad);
+        return intent;
+    }
+
+    /**
+     * Returns PendingIntent for hanging up ongoing phone call. This will typically be used from
+     * Notification context.
+     */
+    /* package */ static PendingIntent createHangUpOngoingCallPendingIntent(Context context) {
+        Intent intent = new Intent(PhoneGlobals.ACTION_HANG_UP_ONGOING_CALL, null,
+                context, NotificationBroadcastReceiver.class);
+        return PendingIntent.getBroadcast(context, 0, intent, 0);
+    }
+
+    /* package */ static PendingIntent getCallBackPendingIntent(Context context, String number) {
+        Intent intent = new Intent(ACTION_CALL_BACK_FROM_NOTIFICATION,
+                Uri.fromParts(Constants.SCHEME_TEL, number, null),
+                context, NotificationBroadcastReceiver.class);
+        return PendingIntent.getBroadcast(context, 0, intent, 0);
+    }
+
+    /* package */ static PendingIntent getSendSmsFromNotificationPendingIntent(
+            Context context, String number) {
+        Intent intent = new Intent(ACTION_SEND_SMS_FROM_NOTIFICATION,
+                Uri.fromParts(Constants.SCHEME_SMSTO, number, null),
+                context, NotificationBroadcastReceiver.class);
+        return PendingIntent.getBroadcast(context, 0, intent, 0);
+    }
+
+    private static String getCallScreenClassName() {
+        return InCallScreen.class.getName();
+    }
+
+    /**
+     * Starts the InCallScreen Activity.
+     */
+    /* package */ void displayCallScreen() {
+        if (VDBG) Log.d(LOG_TAG, "displayCallScreen()...");
+
+        // On non-voice-capable devices we shouldn't ever be trying to
+        // bring up the InCallScreen in the first place.
+        if (!sVoiceCapable) {
+            Log.w(LOG_TAG, "displayCallScreen() not allowed: non-voice-capable device",
+                  new Throwable("stack dump"));  // Include a stack trace since this warning
+                                                 // indicates a bug in our caller
+            return;
+        }
+
+        try {
+            startActivity(createInCallIntent());
+        } catch (ActivityNotFoundException e) {
+            // It's possible that the in-call UI might not exist (like on
+            // non-voice-capable devices), so don't crash if someone
+            // accidentally tries to bring it up...
+            Log.w(LOG_TAG, "displayCallScreen: transition to InCallScreen failed: " + e);
+        }
+        Profiler.callScreenRequested();
+    }
+
+    boolean isSimPinEnabled() {
+        return mIsSimPinEnabled;
+    }
+
+    boolean authenticateAgainstCachedSimPin(String pin) {
+        return (mCachedSimPin != null && mCachedSimPin.equals(pin));
+    }
+
+    void setCachedSimPin(String pin) {
+        mCachedSimPin = pin;
+    }
+
+    void setInCallScreenInstance(InCallScreen inCallScreen) {
+        mInCallScreen = inCallScreen;
+    }
+
+    /**
+     * @return true if the in-call UI is running as the foreground
+     * activity.  (In other words, from the perspective of the
+     * InCallScreen activity, return true between onResume() and
+     * onPause().)
+     *
+     * Note this method will return false if the screen is currently off,
+     * even if the InCallScreen *was* in the foreground just before the
+     * screen turned off.  (This is because the foreground activity is
+     * always "paused" while the screen is off.)
+     */
+    boolean isShowingCallScreen() {
+        if (mInCallScreen == null) return false;
+        return mInCallScreen.isForegroundActivity();
+    }
+
+    /**
+     * @return true if the in-call UI is running as the foreground activity, or,
+     * it went to background due to screen being turned off. This might be useful
+     * to determine if the in-call screen went to background because of other
+     * activities, or its proximity sensor state or manual power-button press.
+     *
+     * Here are some examples.
+     *
+     * - If you want to know if the activity is in foreground or screen is turned off
+     *   from the in-call UI (i.e. though it is not "foreground" anymore it will become
+     *   so after screen being turned on), check
+     *   {@link #isShowingCallScreenForProximity()} is true or not.
+     *   {@link #updateProximitySensorMode(com.android.internal.telephony.PhoneConstants.State)} is
+     *   doing this.
+     *
+     * - If you want to know if the activity is not in foreground just because screen
+     *   is turned off (not due to other activity's interference), check
+     *   {@link #isShowingCallScreen()} is false *and* {@link #isShowingCallScreenForProximity()}
+     *   is true. InCallScreen#onDisconnect() is doing this check.
+     *
+     * @see #isShowingCallScreen()
+     *
+     * TODO: come up with better naming..
+     */
+    boolean isShowingCallScreenForProximity() {
+        if (mInCallScreen == null) return false;
+        return mInCallScreen.isForegroundActivityForProximity();
+    }
+
+    /**
+     * Dismisses the in-call UI.
+     *
+     * This also ensures that you won't be able to get back to the in-call
+     * UI via the BACK button (since this call removes the InCallScreen
+     * from the activity history.)
+     * For OTA Call, it call InCallScreen api to handle OTA Call End scenario
+     * to display OTA Call End screen.
+     */
+    /* package */ void dismissCallScreen() {
+        if (mInCallScreen != null) {
+            if ((TelephonyCapabilities.supportsOtasp(phone)) &&
+                    (mInCallScreen.isOtaCallInActiveState()
+                    || mInCallScreen.isOtaCallInEndState()
+                    || ((cdmaOtaScreenState != null)
+                    && (cdmaOtaScreenState.otaScreenState
+                            != CdmaOtaScreenState.OtaScreenState.OTA_STATUS_UNDEFINED)))) {
+                // TODO: During OTA Call, display should not become dark to
+                // allow user to see OTA UI update. Phone app needs to hold
+                // a SCREEN_DIM_WAKE_LOCK wake lock during the entire OTA call.
+                wakeUpScreen();
+                // If InCallScreen is not in foreground we resume it to show the OTA call end screen
+                // Fire off the InCallScreen intent
+                displayCallScreen();
+
+                mInCallScreen.handleOtaCallEnd();
+                return;
+            } else {
+                mInCallScreen.finish();
+            }
+        }
+    }
+
+    /**
+     * Handles OTASP-related events from the telephony layer.
+     *
+     * While an OTASP call is active, the CallNotifier forwards
+     * OTASP-related telephony events to this method.
+     */
+    void handleOtaspEvent(Message msg) {
+        if (DBG) Log.d(LOG_TAG, "handleOtaspEvent(message " + msg + ")...");
+
+        if (otaUtils == null) {
+            // We shouldn't be getting OTASP events without ever
+            // having started the OTASP call in the first place!
+            Log.w(LOG_TAG, "handleOtaEvents: got an event but otaUtils is null! "
+                  + "message = " + msg);
+            return;
+        }
+
+        otaUtils.onOtaProvisionStatusChanged((AsyncResult) msg.obj);
+    }
+
+    /**
+     * Similarly, handle the disconnect event of an OTASP call
+     * by forwarding it to the OtaUtils instance.
+     */
+    /* package */ void handleOtaspDisconnect() {
+        if (DBG) Log.d(LOG_TAG, "handleOtaspDisconnect()...");
+
+        if (otaUtils == null) {
+            // We shouldn't be getting OTASP events without ever
+            // having started the OTASP call in the first place!
+            Log.w(LOG_TAG, "handleOtaspDisconnect: otaUtils is null!");
+            return;
+        }
+
+        otaUtils.onOtaspDisconnect();
+    }
+
+    /**
+     * Sets the activity responsible for un-PUK-blocking the device
+     * so that we may close it when we receive a positive result.
+     * mPUKEntryActivity is also used to indicate to the device that
+     * we are trying to un-PUK-lock the phone. In other words, iff
+     * it is NOT null, then we are trying to unlock and waiting for
+     * the SIM to move to READY state.
+     *
+     * @param activity is the activity to close when PUK has
+     * finished unlocking. Can be set to null to indicate the unlock
+     * or SIM READYing process is over.
+     */
+    void setPukEntryActivity(Activity activity) {
+        mPUKEntryActivity = activity;
+    }
+
+    Activity getPUKEntryActivity() {
+        return mPUKEntryActivity;
+    }
+
+    /**
+     * Sets the dialog responsible for notifying the user of un-PUK-
+     * blocking - SIM READYing progress, so that we may dismiss it
+     * when we receive a positive result.
+     *
+     * @param dialog indicates the progress dialog informing the user
+     * of the state of the device.  Dismissed upon completion of
+     * READYing process
+     */
+    void setPukEntryProgressDialog(ProgressDialog dialog) {
+        mPUKEntryProgressDialog = dialog;
+    }
+
+    ProgressDialog getPUKEntryProgressDialog() {
+        return mPUKEntryProgressDialog;
+    }
+
+    /**
+     * Controls whether or not the screen is allowed to sleep.
+     *
+     * Once sleep is allowed (WakeState is SLEEP), it will rely on the
+     * settings for the poke lock to determine when to timeout and let
+     * the device sleep {@link PhoneGlobals#setScreenTimeout}.
+     *
+     * @param ws tells the device to how to wake.
+     */
+    /* package */ void requestWakeState(WakeState ws) {
+        if (VDBG) Log.d(LOG_TAG, "requestWakeState(" + ws + ")...");
+        synchronized (this) {
+            if (mWakeState != ws) {
+                switch (ws) {
+                    case PARTIAL:
+                        // acquire the processor wake lock, and release the FULL
+                        // lock if it is being held.
+                        mPartialWakeLock.acquire();
+                        if (mWakeLock.isHeld()) {
+                            mWakeLock.release();
+                        }
+                        break;
+                    case FULL:
+                        // acquire the full wake lock, and release the PARTIAL
+                        // lock if it is being held.
+                        mWakeLock.acquire();
+                        if (mPartialWakeLock.isHeld()) {
+                            mPartialWakeLock.release();
+                        }
+                        break;
+                    case SLEEP:
+                    default:
+                        // release both the PARTIAL and FULL locks.
+                        if (mWakeLock.isHeld()) {
+                            mWakeLock.release();
+                        }
+                        if (mPartialWakeLock.isHeld()) {
+                            mPartialWakeLock.release();
+                        }
+                        break;
+                }
+                mWakeState = ws;
+            }
+        }
+    }
+
+    /**
+     * If we are not currently keeping the screen on, then poke the power
+     * manager to wake up the screen for the user activity timeout duration.
+     */
+    /* package */ void wakeUpScreen() {
+        synchronized (this) {
+            if (mWakeState == WakeState.SLEEP) {
+                if (DBG) Log.d(LOG_TAG, "pulse screen lock");
+                mPowerManager.wakeUp(SystemClock.uptimeMillis());
+            }
+        }
+    }
+
+    /**
+     * Sets the wake state and screen timeout based on the current state
+     * of the phone, and the current state of the in-call UI.
+     *
+     * This method is a "UI Policy" wrapper around
+     * {@link PhoneGlobals#requestWakeState} and {@link PhoneGlobals#setScreenTimeout}.
+     *
+     * It's safe to call this method regardless of the state of the Phone
+     * (e.g. whether or not it's idle), and regardless of the state of the
+     * Phone UI (e.g. whether or not the InCallScreen is active.)
+     */
+    /* package */ void updateWakeState() {
+        PhoneConstants.State state = mCM.getState();
+
+        // True if the in-call UI is the foreground activity.
+        // (Note this will be false if the screen is currently off,
+        // since in that case *no* activity is in the foreground.)
+        boolean isShowingCallScreen = isShowingCallScreen();
+
+        // True if the InCallScreen's DTMF dialer is currently opened.
+        // (Note this does NOT imply whether or not the InCallScreen
+        // itself is visible.)
+        boolean isDialerOpened = (mInCallScreen != null) && mInCallScreen.isDialerOpened();
+
+        // True if the speakerphone is in use.  (If so, we *always* use
+        // the default timeout.  Since the user is obviously not holding
+        // the phone up to his/her face, we don't need to worry about
+        // false touches, and thus don't need to turn the screen off so
+        // aggressively.)
+        // Note that we need to make a fresh call to this method any
+        // time the speaker state changes.  (That happens in
+        // PhoneUtils.turnOnSpeaker().)
+        boolean isSpeakerInUse = (state == PhoneConstants.State.OFFHOOK) && PhoneUtils.isSpeakerOn(this);
+
+        // TODO (bug 1440854): The screen timeout *might* also need to
+        // depend on the bluetooth state, but this isn't as clear-cut as
+        // the speaker state (since while using BT it's common for the
+        // user to put the phone straight into a pocket, in which case the
+        // timeout should probably still be short.)
+
+        if (DBG) Log.d(LOG_TAG, "updateWakeState: callscreen " + isShowingCallScreen
+                       + ", dialer " + isDialerOpened
+                       + ", speaker " + isSpeakerInUse + "...");
+
+        //
+        // Decide whether to force the screen on or not.
+        //
+        // Force the screen to be on if the phone is ringing or dialing,
+        // or if we're displaying the "Call ended" UI for a connection in
+        // the "disconnected" state.
+        // However, if the phone is disconnected while the user is in the
+        // middle of selecting a quick response message, we should not force
+        // the screen to be on.
+        //
+        boolean isRinging = (state == PhoneConstants.State.RINGING);
+        boolean isDialing = (phone.getForegroundCall().getState() == Call.State.DIALING);
+        boolean showingQuickResponseDialog = (mInCallScreen != null) &&
+                mInCallScreen.isQuickResponseDialogShowing();
+        boolean showingDisconnectedConnection =
+                PhoneUtils.hasDisconnectedConnections(phone) && isShowingCallScreen;
+        boolean keepScreenOn = isRinging || isDialing ||
+                (showingDisconnectedConnection && !showingQuickResponseDialog);
+        if (DBG) Log.d(LOG_TAG, "updateWakeState: keepScreenOn = " + keepScreenOn
+                       + " (isRinging " + isRinging
+                       + ", isDialing " + isDialing
+                       + ", showingQuickResponse " + showingQuickResponseDialog
+                       + ", showingDisc " + showingDisconnectedConnection + ")");
+        // keepScreenOn == true means we'll hold a full wake lock:
+        requestWakeState(keepScreenOn ? WakeState.FULL : WakeState.SLEEP);
+    }
+
+    /**
+     * Manually pokes the PowerManager's userActivity method.  Since we
+     * set the {@link WindowManager.LayoutParams#INPUT_FEATURE_DISABLE_USER_ACTIVITY}
+     * flag while the InCallScreen is active when there is no proximity sensor,
+     * we need to do this for touch events that really do count as user activity
+     * (like pressing any onscreen UI elements.)
+     */
+    /* package */ void pokeUserActivity() {
+        if (VDBG) Log.d(LOG_TAG, "pokeUserActivity()...");
+        mPowerManager.userActivity(SystemClock.uptimeMillis(), false);
+    }
+
+    /**
+     * Set when a new outgoing call is beginning, so we can update
+     * the proximity sensor state.
+     * Cleared when the InCallScreen is no longer in the foreground,
+     * in case the call fails without changing the telephony state.
+     */
+    /* package */ void setBeginningCall(boolean beginning) {
+        // Note that we are beginning a new call, for proximity sensor support
+        mBeginningCall = beginning;
+        // Update the Proximity sensor based on mBeginningCall state
+        updateProximitySensorMode(mCM.getState());
+    }
+
+    /**
+     * Updates the wake lock used to control proximity sensor behavior,
+     * based on the current state of the phone.  This method is called
+     * from the CallNotifier on any phone state change.
+     *
+     * On devices that have a proximity sensor, to avoid false touches
+     * during a call, we hold a PROXIMITY_SCREEN_OFF_WAKE_LOCK wake lock
+     * whenever the phone is off hook.  (When held, that wake lock causes
+     * the screen to turn off automatically when the sensor detects an
+     * object close to the screen.)
+     *
+     * This method is a no-op for devices that don't have a proximity
+     * sensor.
+     *
+     * Note this method doesn't care if the InCallScreen is the foreground
+     * activity or not.  That's because we want the proximity sensor to be
+     * enabled any time the phone is in use, to avoid false cheek events
+     * for whatever app you happen to be running.
+     *
+     * Proximity wake lock will *not* be held if any one of the
+     * conditions is true while on a call:
+     * 1) If the audio is routed via Bluetooth
+     * 2) If a wired headset is connected
+     * 3) if the speaker is ON
+     * 4) If the slider is open(i.e. the hardkeyboard is *not* hidden)
+     *
+     * @param state current state of the phone (see {@link Phone#State})
+     */
+    /* package */ void updateProximitySensorMode(PhoneConstants.State state) {
+        if (VDBG) Log.d(LOG_TAG, "updateProximitySensorMode: state = " + state);
+
+        if (proximitySensorModeEnabled()) {
+            synchronized (mProximityWakeLock) {
+                // turn proximity sensor off and turn screen on immediately if
+                // we are using a headset, the keyboard is open, or the device
+                // is being held in a horizontal position.
+                boolean screenOnImmediately = (isHeadsetPlugged()
+                                               || PhoneUtils.isSpeakerOn(this)
+                                               || isBluetoothHeadsetAudioOn()
+                                               || mIsHardKeyboardOpen);
+
+                // We do not keep the screen off when the user is outside in-call screen and we are
+                // horizontal, but we do not force it on when we become horizontal until the
+                // proximity sensor goes negative.
+                boolean horizontal =
+                        (mOrientation == AccelerometerListener.ORIENTATION_HORIZONTAL);
+                screenOnImmediately |= !isShowingCallScreenForProximity() && horizontal;
+
+                // We do not keep the screen off when dialpad is visible, we are horizontal, and
+                // the in-call screen is being shown.
+                // At that moment we're pretty sure users want to use it, instead of letting the
+                // proximity sensor turn off the screen by their hands.
+                boolean dialpadVisible = false;
+                if (mInCallScreen != null) {
+                    dialpadVisible =
+                            mInCallScreen.getUpdatedInCallControlState().dialpadEnabled
+                            && mInCallScreen.getUpdatedInCallControlState().dialpadVisible
+                            && isShowingCallScreen();
+                }
+                screenOnImmediately |= dialpadVisible && horizontal;
+
+                if (((state == PhoneConstants.State.OFFHOOK) || mBeginningCall) && !screenOnImmediately) {
+                    // Phone is in use!  Arrange for the screen to turn off
+                    // automatically when the sensor detects a close object.
+                    if (!mProximityWakeLock.isHeld()) {
+                        if (DBG) Log.d(LOG_TAG, "updateProximitySensorMode: acquiring...");
+                        mProximityWakeLock.acquire();
+                    } else {
+                        if (VDBG) Log.d(LOG_TAG, "updateProximitySensorMode: lock already held.");
+                    }
+                } else {
+                    // Phone is either idle, or ringing.  We don't want any
+                    // special proximity sensor behavior in either case.
+                    if (mProximityWakeLock.isHeld()) {
+                        if (DBG) Log.d(LOG_TAG, "updateProximitySensorMode: releasing...");
+                        // Wait until user has moved the phone away from his head if we are
+                        // releasing due to the phone call ending.
+                        // Qtherwise, turn screen on immediately
+                        int flags =
+                            (screenOnImmediately ? 0 : PowerManager.WAIT_FOR_PROXIMITY_NEGATIVE);
+                        mProximityWakeLock.release(flags);
+                    } else {
+                        if (VDBG) {
+                            Log.d(LOG_TAG, "updateProximitySensorMode: lock already released.");
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    @Override
+    public void orientationChanged(int orientation) {
+        mOrientation = orientation;
+        updateProximitySensorMode(mCM.getState());
+    }
+
+    /**
+     * Notifies the phone app when the phone state changes.
+     *
+     * This method will updates various states inside Phone app (e.g. proximity sensor mode,
+     * accelerometer listener state, update-lock state, etc.)
+     */
+    /* package */ void updatePhoneState(PhoneConstants.State state) {
+        if (state != mLastPhoneState) {
+            mLastPhoneState = state;
+            updateProximitySensorMode(state);
+
+            // Try to acquire or release UpdateLock.
+            //
+            // Watch out: we don't release the lock here when the screen is still in foreground.
+            // At that time InCallScreen will release it on onPause().
+            if (state != PhoneConstants.State.IDLE) {
+                // UpdateLock is a recursive lock, while we may get "acquire" request twice and
+                // "release" request once for a single call (RINGING + OFFHOOK and IDLE).
+                // We need to manually ensure the lock is just acquired once for each (and this
+                // will prevent other possible buggy situations too).
+                if (!mUpdateLock.isHeld()) {
+                    mUpdateLock.acquire();
+                }
+            } else {
+                if (!isShowingCallScreen()) {
+                    if (!mUpdateLock.isHeld()) {
+                        mUpdateLock.release();
+                    }
+                } else {
+                    // For this case InCallScreen will take care of the release() call.
+                }
+            }
+
+            if (mAccelerometerListener != null) {
+                // use accelerometer to augment proximity sensor when in call
+                mOrientation = AccelerometerListener.ORIENTATION_UNKNOWN;
+                mAccelerometerListener.enable(state == PhoneConstants.State.OFFHOOK);
+            }
+            // clear our beginning call flag
+            mBeginningCall = false;
+            // While we are in call, the in-call screen should dismiss the keyguard.
+            // This allows the user to press Home to go directly home without going through
+            // an insecure lock screen.
+            // But we do not want to do this if there is no active call so we do not
+            // bypass the keyguard if the call is not answered or declined.
+            if (mInCallScreen != null) {
+                mInCallScreen.updateKeyguardPolicy(state == PhoneConstants.State.OFFHOOK);
+            }
+        }
+    }
+
+    /* package */ PhoneConstants.State getPhoneState() {
+        return mLastPhoneState;
+    }
+
+    /**
+     * Returns UpdateLock object.
+     */
+    /* package */ UpdateLock getUpdateLock() {
+        return mUpdateLock;
+    }
+
+    /**
+     * @return true if this device supports the "proximity sensor
+     * auto-lock" feature while in-call (see updateProximitySensorMode()).
+     */
+    /* package */ boolean proximitySensorModeEnabled() {
+        return (mProximityWakeLock != null);
+    }
+
+    KeyguardManager getKeyguardManager() {
+        return mKeyguardManager;
+    }
+
+    private void onMMIComplete(AsyncResult r) {
+        if (VDBG) Log.d(LOG_TAG, "onMMIComplete()...");
+        MmiCode mmiCode = (MmiCode) r.result;
+        PhoneUtils.displayMMIComplete(phone, getInstance(), mmiCode, null, null);
+    }
+
+    private void initForNewRadioTechnology() {
+        if (DBG) Log.d(LOG_TAG, "initForNewRadioTechnology...");
+
+         if (phone.getPhoneType() == PhoneConstants.PHONE_TYPE_CDMA) {
+            // Create an instance of CdmaPhoneCallState and initialize it to IDLE
+            cdmaPhoneCallState = new CdmaPhoneCallState();
+            cdmaPhoneCallState.CdmaPhoneCallStateInit();
+        }
+        if (TelephonyCapabilities.supportsOtasp(phone)) {
+            //create instances of CDMA OTA data classes
+            if (cdmaOtaProvisionData == null) {
+                cdmaOtaProvisionData = new OtaUtils.CdmaOtaProvisionData();
+            }
+            if (cdmaOtaConfigData == null) {
+                cdmaOtaConfigData = new OtaUtils.CdmaOtaConfigData();
+            }
+            if (cdmaOtaScreenState == null) {
+                cdmaOtaScreenState = new OtaUtils.CdmaOtaScreenState();
+            }
+            if (cdmaOtaInCallScreenUiState == null) {
+                cdmaOtaInCallScreenUiState = new OtaUtils.CdmaOtaInCallScreenUiState();
+            }
+        } else {
+            //Clean up OTA data in GSM/UMTS. It is valid only for CDMA
+            clearOtaState();
+        }
+
+        ringer.updateRingerContextAfterRadioTechnologyChange(this.phone);
+        notifier.updateCallNotifierRegistrationsAfterRadioTechnologyChange();
+        if (mBluetoothPhone != null) {
+            try {
+                mBluetoothPhone.updateBtHandsfreeAfterRadioTechnologyChange();
+            } catch (RemoteException e) {
+                Log.e(LOG_TAG, Log.getStackTraceString(new Throwable()));
+            }
+        }
+        if (mInCallScreen != null) {
+            mInCallScreen.updateAfterRadioTechnologyChange();
+        }
+
+        // Update registration for ICC status after radio technology change
+        IccCard sim = phone.getIccCard();
+        if (sim != null) {
+            if (DBG) Log.d(LOG_TAG, "Update registration for ICC status...");
+
+            //Register all events new to the new active phone
+            sim.registerForNetworkLocked(mHandler, EVENT_SIM_NETWORK_LOCKED, null);
+        }
+    }
+
+
+    /**
+     * @return true if a wired headset is currently plugged in.
+     *
+     * @see Intent.ACTION_HEADSET_PLUG (which we listen for in mReceiver.onReceive())
+     */
+    boolean isHeadsetPlugged() {
+        return mIsHeadsetPlugged;
+    }
+
+    /**
+     * @return true if the onscreen UI should currently be showing the
+     * special "bluetooth is active" indication in a couple of places (in
+     * which UI elements turn blue and/or show the bluetooth logo.)
+     *
+     * This depends on the BluetoothHeadset state *and* the current
+     * telephony state; see shouldShowBluetoothIndication().
+     *
+     * @see CallCard
+     * @see NotificationMgr.updateInCallNotification
+     */
+    /* package */ boolean showBluetoothIndication() {
+        return mShowBluetoothIndication;
+    }
+
+    /**
+     * Recomputes the mShowBluetoothIndication flag based on the current
+     * bluetooth state and current telephony state.
+     *
+     * This needs to be called any time the bluetooth headset state or the
+     * telephony state changes.
+     *
+     * @param forceUiUpdate if true, force the UI elements that care
+     *                      about this flag to update themselves.
+     */
+    /* package */ void updateBluetoothIndication(boolean forceUiUpdate) {
+        mShowBluetoothIndication = shouldShowBluetoothIndication(mBluetoothHeadsetState,
+                                                                 mBluetoothHeadsetAudioState,
+                                                                 mCM);
+        if (forceUiUpdate) {
+            // Post Handler messages to the various components that might
+            // need to be refreshed based on the new state.
+            if (isShowingCallScreen()) mInCallScreen.requestUpdateBluetoothIndication();
+            if (DBG) Log.d (LOG_TAG, "- updating in-call notification for BT state change...");
+            mHandler.sendEmptyMessage(EVENT_UPDATE_INCALL_NOTIFICATION);
+        }
+
+        // Update the Proximity sensor based on Bluetooth audio state
+        updateProximitySensorMode(mCM.getState());
+    }
+
+    /**
+     * UI policy helper function for the couple of places in the UI that
+     * have some way of indicating that "bluetooth is in use."
+     *
+     * @return true if the onscreen UI should indicate that "bluetooth is in use",
+     *         based on the specified bluetooth headset state, and the
+     *         current state of the phone.
+     * @see showBluetoothIndication()
+     */
+    private static boolean shouldShowBluetoothIndication(int bluetoothState,
+                                                         int bluetoothAudioState,
+                                                         CallManager cm) {
+        // We want the UI to indicate that "bluetooth is in use" in two
+        // slightly different cases:
+        //
+        // (a) The obvious case: if a bluetooth headset is currently in
+        //     use for an ongoing call.
+        //
+        // (b) The not-so-obvious case: if an incoming call is ringing,
+        //     and we expect that audio *will* be routed to a bluetooth
+        //     headset once the call is answered.
+
+        switch (cm.getState()) {
+            case OFFHOOK:
+                // This covers normal active calls, and also the case if
+                // the foreground call is DIALING or ALERTING.  In this
+                // case, bluetooth is considered "active" if a headset
+                // is connected *and* audio is being routed to it.
+                return ((bluetoothState == BluetoothHeadset.STATE_CONNECTED)
+                        && (bluetoothAudioState == BluetoothHeadset.STATE_AUDIO_CONNECTED));
+
+            case RINGING:
+                // If an incoming call is ringing, we're *not* yet routing
+                // audio to the headset (since there's no in-call audio
+                // yet!)  In this case, if a bluetooth headset is
+                // connected at all, we assume that it'll become active
+                // once the user answers the phone.
+                return (bluetoothState == BluetoothHeadset.STATE_CONNECTED);
+
+            default:  // Presumably IDLE
+                return false;
+        }
+    }
+
+
+    /**
+     * Receiver for misc intent broadcasts the Phone app cares about.
+     */
+    private class PhoneAppBroadcastReceiver extends BroadcastReceiver {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            String action = intent.getAction();
+            if (action.equals(Intent.ACTION_AIRPLANE_MODE_CHANGED)) {
+                boolean enabled = System.getInt(getContentResolver(),
+                        System.AIRPLANE_MODE_ON, 0) == 0;
+                phone.setRadioPower(enabled);
+            } else if (action.equals(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED)) {
+                mBluetoothHeadsetState = intent.getIntExtra(BluetoothHeadset.EXTRA_STATE,
+                                                          BluetoothHeadset.STATE_DISCONNECTED);
+                if (VDBG) Log.d(LOG_TAG, "mReceiver: HEADSET_STATE_CHANGED_ACTION");
+                if (VDBG) Log.d(LOG_TAG, "==> new state: " + mBluetoothHeadsetState);
+                updateBluetoothIndication(true);  // Also update any visible UI if necessary
+            } else if (action.equals(BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED)) {
+                mBluetoothHeadsetAudioState =
+                        intent.getIntExtra(BluetoothHeadset.EXTRA_STATE,
+                                           BluetoothHeadset.STATE_AUDIO_DISCONNECTED);
+                if (VDBG) Log.d(LOG_TAG, "mReceiver: HEADSET_AUDIO_STATE_CHANGED_ACTION");
+                if (VDBG) Log.d(LOG_TAG, "==> new state: " + mBluetoothHeadsetAudioState);
+                updateBluetoothIndication(true);  // Also update any visible UI if necessary
+            } else if (action.equals(TelephonyIntents.ACTION_ANY_DATA_CONNECTION_STATE_CHANGED)) {
+                if (VDBG) Log.d(LOG_TAG, "mReceiver: ACTION_ANY_DATA_CONNECTION_STATE_CHANGED");
+                if (VDBG) Log.d(LOG_TAG, "- state: " + intent.getStringExtra(PhoneConstants.STATE_KEY));
+                if (VDBG) Log.d(LOG_TAG, "- reason: "
+                                + intent.getStringExtra(PhoneConstants.STATE_CHANGE_REASON_KEY));
+
+                // The "data disconnected due to roaming" notification is shown
+                // if (a) you have the "data roaming" feature turned off, and
+                // (b) you just lost data connectivity because you're roaming.
+                boolean disconnectedDueToRoaming =
+                        !phone.getDataRoamingEnabled()
+                        && "DISCONNECTED".equals(intent.getStringExtra(PhoneConstants.STATE_KEY))
+                        && Phone.REASON_ROAMING_ON.equals(
+                            intent.getStringExtra(PhoneConstants.STATE_CHANGE_REASON_KEY));
+                mHandler.sendEmptyMessage(disconnectedDueToRoaming
+                                          ? EVENT_DATA_ROAMING_DISCONNECTED
+                                          : EVENT_DATA_ROAMING_OK);
+            } else if (action.equals(Intent.ACTION_HEADSET_PLUG)) {
+                if (VDBG) Log.d(LOG_TAG, "mReceiver: ACTION_HEADSET_PLUG");
+                if (VDBG) Log.d(LOG_TAG, "    state: " + intent.getIntExtra("state", 0));
+                if (VDBG) Log.d(LOG_TAG, "    name: " + intent.getStringExtra("name"));
+                mIsHeadsetPlugged = (intent.getIntExtra("state", 0) == 1);
+                mHandler.sendMessage(mHandler.obtainMessage(EVENT_WIRED_HEADSET_PLUG, 0));
+            } else if ((action.equals(TelephonyIntents.ACTION_SIM_STATE_CHANGED)) &&
+                    (mPUKEntryActivity != null)) {
+                // if an attempt to un-PUK-lock the device was made, while we're
+                // receiving this state change notification, notify the handler.
+                // NOTE: This is ONLY triggered if an attempt to un-PUK-lock has
+                // been attempted.
+                mHandler.sendMessage(mHandler.obtainMessage(EVENT_SIM_STATE_CHANGED,
+                        intent.getStringExtra(IccCardConstants.INTENT_KEY_ICC_STATE)));
+            } else if (action.equals(TelephonyIntents.ACTION_RADIO_TECHNOLOGY_CHANGED)) {
+                String newPhone = intent.getStringExtra(PhoneConstants.PHONE_NAME_KEY);
+                Log.d(LOG_TAG, "Radio technology switched. Now " + newPhone + " is active.");
+                initForNewRadioTechnology();
+            } else if (action.equals(TelephonyIntents.ACTION_SERVICE_STATE_CHANGED)) {
+                handleServiceStateChanged(intent);
+            } else if (action.equals(TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED)) {
+                if (TelephonyCapabilities.supportsEcm(phone)) {
+                    Log.d(LOG_TAG, "Emergency Callback Mode arrived in PhoneApp.");
+                    // Start Emergency Callback Mode service
+                    if (intent.getBooleanExtra("phoneinECMState", false)) {
+                        context.startService(new Intent(context,
+                                EmergencyCallbackModeService.class));
+                    }
+                } else {
+                    // It doesn't make sense to get ACTION_EMERGENCY_CALLBACK_MODE_CHANGED
+                    // on a device that doesn't support ECM in the first place.
+                    Log.e(LOG_TAG, "Got ACTION_EMERGENCY_CALLBACK_MODE_CHANGED, "
+                          + "but ECM isn't supported for phone: " + phone.getPhoneName());
+                }
+            } else if (action.equals(Intent.ACTION_DOCK_EVENT)) {
+                mDockState = intent.getIntExtra(Intent.EXTRA_DOCK_STATE,
+                        Intent.EXTRA_DOCK_STATE_UNDOCKED);
+                if (VDBG) Log.d(LOG_TAG, "ACTION_DOCK_EVENT -> mDockState = " + mDockState);
+                mHandler.sendMessage(mHandler.obtainMessage(EVENT_DOCK_STATE_CHANGED, 0));
+            } else if (action.equals(TtyIntent.TTY_PREFERRED_MODE_CHANGE_ACTION)) {
+                mPreferredTtyMode = intent.getIntExtra(TtyIntent.TTY_PREFFERED_MODE,
+                                                       Phone.TTY_MODE_OFF);
+                if (VDBG) Log.d(LOG_TAG, "mReceiver: TTY_PREFERRED_MODE_CHANGE_ACTION");
+                if (VDBG) Log.d(LOG_TAG, "    mode: " + mPreferredTtyMode);
+                mHandler.sendMessage(mHandler.obtainMessage(EVENT_TTY_PREFERRED_MODE_CHANGED, 0));
+            } else if (action.equals(AudioManager.RINGER_MODE_CHANGED_ACTION)) {
+                int ringerMode = intent.getIntExtra(AudioManager.EXTRA_RINGER_MODE,
+                        AudioManager.RINGER_MODE_NORMAL);
+                if (ringerMode == AudioManager.RINGER_MODE_SILENT) {
+                    notifier.silenceRinger();
+                }
+            }
+        }
+    }
+
+    /**
+     * Broadcast receiver for the ACTION_MEDIA_BUTTON broadcast intent.
+     *
+     * This functionality isn't lumped in with the other intents in
+     * PhoneAppBroadcastReceiver because we instantiate this as a totally
+     * separate BroadcastReceiver instance, since we need to manually
+     * adjust its IntentFilter's priority (to make sure we get these
+     * intents *before* the media player.)
+     */
+    private class MediaButtonBroadcastReceiver extends BroadcastReceiver {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            KeyEvent event = (KeyEvent) intent.getParcelableExtra(Intent.EXTRA_KEY_EVENT);
+            if (VDBG) Log.d(LOG_TAG,
+                           "MediaButtonBroadcastReceiver.onReceive()...  event = " + event);
+            if ((event != null)
+                && (event.getKeyCode() == KeyEvent.KEYCODE_HEADSETHOOK)) {
+                if (VDBG) Log.d(LOG_TAG, "MediaButtonBroadcastReceiver: HEADSETHOOK");
+                boolean consumed = PhoneUtils.handleHeadsetHook(phone, event);
+                if (VDBG) Log.d(LOG_TAG, "==> handleHeadsetHook(): consumed = " + consumed);
+                if (consumed) {
+                    // If a headset is attached and the press is consumed, also update
+                    // any UI items (such as an InCallScreen mute button) that may need to
+                    // be updated if their state changed.
+                    updateInCallScreen();  // Has no effect if the InCallScreen isn't visible
+                    abortBroadcast();
+                }
+            } else {
+                if (mCM.getState() != PhoneConstants.State.IDLE) {
+                    // If the phone is anything other than completely idle,
+                    // then we consume and ignore any media key events,
+                    // Otherwise it is too easy to accidentally start
+                    // playing music while a phone call is in progress.
+                    if (VDBG) Log.d(LOG_TAG, "MediaButtonBroadcastReceiver: consumed");
+                    abortBroadcast();
+                }
+            }
+        }
+    }
+
+    /**
+     * Accepts broadcast Intents which will be prepared by {@link NotificationMgr} and thus
+     * sent from framework's notification mechanism (which is outside Phone context).
+     * This should be visible from outside, but shouldn't be in "exported" state.
+     *
+     * TODO: If possible merge this into PhoneAppBroadcastReceiver.
+     */
+    public static class NotificationBroadcastReceiver extends BroadcastReceiver {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            String action = intent.getAction();
+            // TODO: use "if (VDBG)" here.
+            Log.d(LOG_TAG, "Broadcast from Notification: " + action);
+
+            if (action.equals(ACTION_HANG_UP_ONGOING_CALL)) {
+                PhoneUtils.hangup(PhoneGlobals.getInstance().mCM);
+            } else if (action.equals(ACTION_CALL_BACK_FROM_NOTIFICATION)) {
+                // Collapse the expanded notification and the notification item itself.
+                closeSystemDialogs(context);
+                clearMissedCallNotification(context);
+
+                Intent callIntent = new Intent(Intent.ACTION_CALL_PRIVILEGED, intent.getData());
+                callIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
+                        | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
+                context.startActivity(callIntent);
+            } else if (action.equals(ACTION_SEND_SMS_FROM_NOTIFICATION)) {
+                // Collapse the expanded notification and the notification item itself.
+                closeSystemDialogs(context);
+                clearMissedCallNotification(context);
+
+                Intent smsIntent = new Intent(Intent.ACTION_SENDTO, intent.getData());
+                smsIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+                context.startActivity(smsIntent);
+            } else {
+                Log.w(LOG_TAG, "Received hang-up request from notification,"
+                        + " but there's no call the system can hang up.");
+            }
+        }
+
+        private void closeSystemDialogs(Context context) {
+            Intent intent = new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
+            context.sendBroadcastAsUser(intent, UserHandle.ALL);
+        }
+
+        private void clearMissedCallNotification(Context context) {
+            Intent clearIntent = new Intent(context, ClearMissedCallsService.class);
+            clearIntent.setAction(ClearMissedCallsService.ACTION_CLEAR_MISSED_CALLS);
+            context.startService(clearIntent);
+        }
+    }
+
+    private void handleServiceStateChanged(Intent intent) {
+        /**
+         * This used to handle updating EriTextWidgetProvider this routine
+         * and and listening for ACTION_SERVICE_STATE_CHANGED intents could
+         * be removed. But leaving just in case it might be needed in the near
+         * future.
+         */
+
+        // If service just returned, start sending out the queued messages
+        ServiceState ss = ServiceState.newFromBundle(intent.getExtras());
+
+        if (ss != null) {
+            int state = ss.getState();
+            notificationMgr.updateNetworkSelection(state);
+        }
+    }
+
+    public boolean isOtaCallInActiveState() {
+        boolean otaCallActive = false;
+        if (mInCallScreen != null) {
+            otaCallActive = mInCallScreen.isOtaCallInActiveState();
+        }
+        if (VDBG) Log.d(LOG_TAG, "- isOtaCallInActiveState " + otaCallActive);
+        return otaCallActive;
+    }
+
+    public boolean isOtaCallInEndState() {
+        boolean otaCallEnded = false;
+        if (mInCallScreen != null) {
+            otaCallEnded = mInCallScreen.isOtaCallInEndState();
+        }
+        if (VDBG) Log.d(LOG_TAG, "- isOtaCallInEndState " + otaCallEnded);
+        return otaCallEnded;
+    }
+
+    // it is safe to call clearOtaState() even if the InCallScreen isn't active
+    public void clearOtaState() {
+        if (DBG) Log.d(LOG_TAG, "- clearOtaState ...");
+        if ((mInCallScreen != null)
+                && (otaUtils != null)) {
+            otaUtils.cleanOtaScreen(true);
+            if (DBG) Log.d(LOG_TAG, "  - clearOtaState clears OTA screen");
+        }
+    }
+
+    // it is safe to call dismissOtaDialogs() even if the InCallScreen isn't active
+    public void dismissOtaDialogs() {
+        if (DBG) Log.d(LOG_TAG, "- dismissOtaDialogs ...");
+        if ((mInCallScreen != null)
+                && (otaUtils != null)) {
+            otaUtils.dismissAllOtaDialogs();
+            if (DBG) Log.d(LOG_TAG, "  - dismissOtaDialogs clears OTA dialogs");
+        }
+    }
+
+    // it is safe to call clearInCallScreenMode() even if the InCallScreen isn't active
+    public void clearInCallScreenMode() {
+        if (DBG) Log.d(LOG_TAG, "- clearInCallScreenMode ...");
+        if (mInCallScreen != null) {
+            mInCallScreen.resetInCallScreenMode();
+        }
+    }
+
+    /**
+     * Force the in-call UI to refresh itself, if it's currently visible.
+     *
+     * This method can be used any time there's a state change anywhere in
+     * the phone app that needs to be reflected in the onscreen UI.
+     *
+     * Note that it's *not* necessary to manually refresh the in-call UI
+     * (via this method) for regular telephony state changes like
+     * DIALING -> ALERTING -> ACTIVE, since the InCallScreen already
+     * listens for those state changes itself.
+     *
+     * This method does *not* force the in-call UI to come up if it's not
+     * already visible.  To do that, use displayCallScreen().
+     */
+    /* package */ void updateInCallScreen() {
+        if (DBG) Log.d(LOG_TAG, "- updateInCallScreen()...");
+        if (mInCallScreen != null) {
+            // Post an updateScreen() request.  Note that the
+            // updateScreen() call will end up being a no-op if the
+            // InCallScreen isn't the foreground activity.
+            mInCallScreen.requestUpdateScreen();
+        }
+    }
+
+    private void handleQueryTTYModeResponse(Message msg) {
+        AsyncResult ar = (AsyncResult) msg.obj;
+        if (ar.exception != null) {
+            if (DBG) Log.d(LOG_TAG, "handleQueryTTYModeResponse: Error getting TTY state.");
+        } else {
+            if (DBG) Log.d(LOG_TAG,
+                           "handleQueryTTYModeResponse: TTY enable state successfully queried.");
+
+            int ttymode = ((int[]) ar.result)[0];
+            if (DBG) Log.d(LOG_TAG, "handleQueryTTYModeResponse:ttymode=" + ttymode);
+
+            Intent ttyModeChanged = new Intent(TtyIntent.TTY_ENABLED_CHANGE_ACTION);
+            ttyModeChanged.putExtra("ttyEnabled", ttymode != Phone.TTY_MODE_OFF);
+            sendBroadcastAsUser(ttyModeChanged, UserHandle.ALL);
+
+            String audioTtyMode;
+            switch (ttymode) {
+            case Phone.TTY_MODE_FULL:
+                audioTtyMode = "tty_full";
+                break;
+            case Phone.TTY_MODE_VCO:
+                audioTtyMode = "tty_vco";
+                break;
+            case Phone.TTY_MODE_HCO:
+                audioTtyMode = "tty_hco";
+                break;
+            case Phone.TTY_MODE_OFF:
+            default:
+                audioTtyMode = "tty_off";
+                break;
+            }
+            AudioManager audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
+            audioManager.setParameters("tty_mode="+audioTtyMode);
+        }
+    }
+
+    private void handleSetTTYModeResponse(Message msg) {
+        AsyncResult ar = (AsyncResult) msg.obj;
+
+        if (ar.exception != null) {
+            if (DBG) Log.d (LOG_TAG,
+                    "handleSetTTYModeResponse: Error setting TTY mode, ar.exception"
+                    + ar.exception);
+        }
+        phone.queryTTYMode(mHandler.obtainMessage(EVENT_TTY_MODE_GET));
+    }
+
+    /**
+     * "Call origin" may be used by Contacts app to specify where the phone call comes from.
+     * Currently, the only permitted value for this extra is {@link #ALLOWED_EXTRA_CALL_ORIGIN}.
+     * Any other value will be ignored, to make sure that malicious apps can't trick the in-call
+     * UI into launching some random other app after a call ends.
+     *
+     * TODO: make this more generic. Note that we should let the "origin" specify its package
+     * while we are now assuming it is "com.android.contacts"
+     */
+    public static final String EXTRA_CALL_ORIGIN = "com.android.phone.CALL_ORIGIN";
+    private static final String DEFAULT_CALL_ORIGIN_PACKAGE = "com.android.contacts";
+    private static final String ALLOWED_EXTRA_CALL_ORIGIN =
+            "com.android.contacts.activities.DialtactsActivity";
+    /**
+     * Used to determine if the preserved call origin is fresh enough.
+     */
+    private static final long CALL_ORIGIN_EXPIRATION_MILLIS = 30 * 1000;
+
+    public void setLatestActiveCallOrigin(String callOrigin) {
+        inCallUiState.latestActiveCallOrigin = callOrigin;
+        if (callOrigin != null) {
+            inCallUiState.latestActiveCallOriginTimeStamp = SystemClock.elapsedRealtime();
+        } else {
+            inCallUiState.latestActiveCallOriginTimeStamp = 0;
+        }
+    }
+
+    /**
+     * Reset call origin depending on its timestamp.
+     *
+     * See if the current call origin preserved by the app is fresh enough or not. If it is,
+     * previous call origin will be used as is. If not, call origin will be reset.
+     *
+     * This will be effective especially for 3rd party apps which want to bypass phone calls with
+     * their own telephone lines. In that case Phone app may finish the phone call once and make
+     * another for the external apps, which will drop call origin information in Intent.
+     * Even in that case we are sure the second phone call should be initiated just after the first
+     * phone call, so here we restore it from the previous information iff the second call is done
+     * fairly soon.
+     */
+    public void resetLatestActiveCallOrigin() {
+        final long callOriginTimestamp = inCallUiState.latestActiveCallOriginTimeStamp;
+        final long currentTimestamp = SystemClock.elapsedRealtime();
+        if (VDBG) {
+            Log.d(LOG_TAG, "currentTimeMillis: " + currentTimestamp
+                    + ", saved timestamp for call origin: " + callOriginTimestamp);
+        }
+        if (inCallUiState.latestActiveCallOriginTimeStamp > 0
+                && (currentTimestamp - callOriginTimestamp < CALL_ORIGIN_EXPIRATION_MILLIS)) {
+            if (VDBG) {
+                Log.d(LOG_TAG, "Resume previous call origin (" +
+                        inCallUiState.latestActiveCallOrigin + ")");
+            }
+            // Do nothing toward call origin itself but update the timestamp just in case.
+            inCallUiState.latestActiveCallOriginTimeStamp = currentTimestamp;
+        } else {
+            if (VDBG) Log.d(LOG_TAG, "Drop previous call origin and set the current one to null");
+            setLatestActiveCallOrigin(null);
+        }
+    }
+
+    /**
+     * @return Intent which will be used when in-call UI is shown and the phone call is hang up.
+     * By default CallLog screen will be introduced, but the destination may change depending on
+     * its latest call origin state.
+     */
+    public Intent createPhoneEndIntentUsingCallOrigin() {
+        if (TextUtils.equals(inCallUiState.latestActiveCallOrigin, ALLOWED_EXTRA_CALL_ORIGIN)) {
+            if (VDBG) Log.d(LOG_TAG, "Valid latestActiveCallOrigin("
+                    + inCallUiState.latestActiveCallOrigin + ") was found. "
+                    + "Go back to the previous screen.");
+            // Right now we just launch the Activity which launched in-call UI. Note that we're
+            // assuming the origin is from "com.android.contacts", which may be incorrect in the
+            // future.
+            final Intent intent = new Intent();
+            intent.setClassName(DEFAULT_CALL_ORIGIN_PACKAGE, inCallUiState.latestActiveCallOrigin);
+            return intent;
+        } else {
+            if (VDBG) Log.d(LOG_TAG, "Current latestActiveCallOrigin ("
+                    + inCallUiState.latestActiveCallOrigin + ") is not valid. "
+                    + "Just use CallLog as a default destination.");
+            return PhoneGlobals.createCallLogIntent();
+        }
+    }
+
+    /** Service connection */
+    private final ServiceConnection mBluetoothPhoneConnection = new ServiceConnection() {
+
+        /** Handle the task of binding the local object to the service */
+        public void onServiceConnected(ComponentName className, IBinder service) {
+            Log.i(LOG_TAG, "Headset phone created, binding local service.");
+            mBluetoothPhone = IBluetoothHeadsetPhone.Stub.asInterface(service);
+        }
+
+        /** Handle the task of cleaning up the local binding */
+        public void onServiceDisconnected(ComponentName className) {
+            Log.i(LOG_TAG, "Headset phone disconnected, cleaning local binding.");
+            mBluetoothPhone = null;
+        }
+    };
+}
diff --git a/src/com/android/phone/PhoneInterfaceManager.java b/src/com/android/phone/PhoneInterfaceManager.java
index a5bb130..441270a 100644
--- a/src/com/android/phone/PhoneInterfaceManager.java
+++ b/src/com/android/phone/PhoneInterfaceManager.java
@@ -16,6 +16,7 @@
 
 package com.android.phone;
 
+import android.app.ActivityManager;
 import android.content.ActivityNotFoundException;
 import android.content.Context;
 import android.content.Intent;
@@ -27,11 +28,12 @@
 import android.os.Handler;
 import android.os.Looper;
 import android.os.Message;
+import android.os.Process;
 import android.os.ServiceManager;
+import android.os.UserHandle;
 import android.telephony.NeighboringCellInfo;
 import android.telephony.CellInfo;
 import android.telephony.ServiceState;
-import android.telephony.TelephonyManager;
 import android.text.TextUtils;
 import android.util.Log;
 
@@ -50,7 +52,8 @@
  */
 public class PhoneInterfaceManager extends ITelephony.Stub {
     private static final String LOG_TAG = "PhoneInterfaceManager";
-    private static final boolean DBG = (PhoneApp.DBG_LEVEL >= 2);
+    private static final boolean DBG = (PhoneGlobals.DBG_LEVEL >= 2);
+    private static final boolean DBG_LOC = false;
 
     // Message codes used with mMainThreadHandler
     private static final int CMD_HANDLE_PIN_MMI = 1;
@@ -63,7 +66,7 @@
     /** The singleton instance. */
     private static PhoneInterfaceManager sInstance;
 
-    PhoneApp mApp;
+    PhoneGlobals mApp;
     Phone mPhone;
     CallManager mCM;
     MainThreadHandler mMainThreadHandler;
@@ -213,7 +216,7 @@
      * Initialize the singleton PhoneInterfaceManager instance.
      * This is only done once, at startup, from PhoneApp.onCreate().
      */
-    /* package */ static PhoneInterfaceManager init(PhoneApp app, Phone phone) {
+    /* package */ static PhoneInterfaceManager init(PhoneGlobals app, Phone phone) {
         synchronized (PhoneInterfaceManager.class) {
             if (sInstance == null) {
                 sInstance = new PhoneInterfaceManager(app, phone);
@@ -225,10 +228,10 @@
     }
 
     /** Private constructor; @see init() */
-    private PhoneInterfaceManager(PhoneApp app, Phone phone) {
+    private PhoneInterfaceManager(PhoneGlobals app, Phone phone) {
         mApp = app;
         mPhone = phone;
-        mCM = PhoneApp.getInstance().mCM;
+        mCM = PhoneGlobals.getInstance().mCM;
         mMainThreadHandler = new MainThreadHandler();
         publish();
     }
@@ -283,7 +286,7 @@
 
     private boolean showCallScreenInternal(boolean specifyInitialDialpadState,
                                            boolean initialDialpadState) {
-        if (!PhoneApp.sVoiceCapable) {
+        if (!PhoneGlobals.sVoiceCapable) {
             // Never allow the InCallScreen to appear on data-only devices.
             return false;
         }
@@ -295,9 +298,9 @@
         try {
             Intent intent;
             if (specifyInitialDialpadState) {
-                intent = PhoneApp.createInCallIntent(initialDialpadState);
+                intent = PhoneGlobals.createInCallIntent(initialDialpadState);
             } else {
-                intent = PhoneApp.createInCallIntent();
+                intent = PhoneGlobals.createInCallIntent();
             }
             try {
                 mApp.startActivity(intent);
@@ -420,7 +423,7 @@
 
     public boolean isSimPinEnabled() {
         enforceReadPermission();
-        return (PhoneApp.getInstance().isSimPinEnabled());
+        return (PhoneGlobals.getInstance().isSimPinEnabled());
     }
 
     public boolean supplyPin(String pin) {
@@ -596,6 +599,7 @@
         return DefaultPhoneNotifier.convertDataActivityState(mPhone.getDataActivityState());
     }
 
+    @Override
     public Bundle getCellLocation() {
         try {
             mApp.enforceCallingOrSelfPermission(
@@ -607,23 +611,33 @@
             mApp.enforceCallingOrSelfPermission(
                 android.Manifest.permission.ACCESS_COARSE_LOCATION, null);
         }
-        Bundle data = new Bundle();
-        mPhone.getCellLocation().fillInNotifierBundle(data);
-        return data;
+
+        if (checkIfCallerIsSelfOrForegoundUser()) {
+            if (DBG_LOC) log("getCellLocation: is active user");
+            Bundle data = new Bundle();
+            mPhone.getCellLocation().fillInNotifierBundle(data);
+            return data;
+        } else {
+            if (DBG_LOC) log("getCellLocation: suppress non-active user");
+            return null;
+        }
     }
 
+    @Override
     public void enableLocationUpdates() {
         mApp.enforceCallingOrSelfPermission(
                 android.Manifest.permission.CONTROL_LOCATION_UPDATES, null);
         mPhone.enableLocationUpdates();
     }
 
+    @Override
     public void disableLocationUpdates() {
         mApp.enforceCallingOrSelfPermission(
                 android.Manifest.permission.CONTROL_LOCATION_UPDATES, null);
         mPhone.disableLocationUpdates();
     }
 
+    @Override
     @SuppressWarnings("unchecked")
     public List<NeighboringCellInfo> getNeighboringCellInfo() {
         try {
@@ -638,19 +652,26 @@
                     android.Manifest.permission.ACCESS_COARSE_LOCATION, null);
         }
 
-        ArrayList<NeighboringCellInfo> cells = null;
+        if (checkIfCallerIsSelfOrForegoundUser()) {
+            if (DBG_LOC) log("getNeighboringCellInfo: is active user");
 
-        try {
-            cells = (ArrayList<NeighboringCellInfo>) sendRequest(
-                    CMD_HANDLE_NEIGHBORING_CELL, null);
-        } catch (RuntimeException e) {
-            Log.e(LOG_TAG, "getNeighboringCellInfo " + e);
+            ArrayList<NeighboringCellInfo> cells = null;
+
+            try {
+                cells = (ArrayList<NeighboringCellInfo>) sendRequest(
+                        CMD_HANDLE_NEIGHBORING_CELL, null);
+            } catch (RuntimeException e) {
+                Log.e(LOG_TAG, "getNeighboringCellInfo " + e);
+            }
+            return cells;
+        } else {
+            if (DBG_LOC) log("getNeighboringCellInfo: suppress non-active user");
+            return null;
         }
-
-        return (List <NeighboringCellInfo>) cells;
     }
 
 
+    @Override
     public List<CellInfo> getAllCellInfo() {
         try {
             mApp.enforceCallingOrSelfPermission(
@@ -663,14 +684,51 @@
                 android.Manifest.permission.ACCESS_COARSE_LOCATION, null);
         }
 
-        // TODO return cell info list got from mPhone
-        return null;
+        if (checkIfCallerIsSelfOrForegoundUser()) {
+            if (DBG_LOC) log("getAllCellInfo: is active user");
+            return mPhone.getAllCellInfo();
+        } else {
+            if (DBG_LOC) log("getAllCellInfo: suppress non-active user");
+            return null;
+        }
     }
 
     //
     // Internal helper methods.
     //
 
+    private boolean checkIfCallerIsSelfOrForegoundUser() {
+        boolean ok;
+
+        boolean self = Binder.getCallingUid() == Process.myUid();
+        if (!self) {
+            // Get the caller's user id then clear the calling identity
+            // which will be restored in the finally clause.
+            int callingUser = UserHandle.getCallingUserId();
+            long ident = Binder.clearCallingIdentity();
+
+            try {
+                // With calling identity cleared the current user is the foreground user.
+                int foregroundUser = ActivityManager.getCurrentUser();
+                ok = (foregroundUser == callingUser);
+                if (DBG_LOC) {
+                    log("checkIfCallerIsSelfOrForegoundUser: foregroundUser=" + foregroundUser
+                            + " callingUser=" + callingUser + " ok=" + ok);
+                }
+            } catch (Exception ex) {
+                if (DBG_LOC) loge("checkIfCallerIsSelfOrForegoundUser: Exception ex=" + ex);
+                ok = false;
+            } finally {
+                Binder.restoreCallingIdentity(ident);
+            }
+        } else {
+            if (DBG_LOC) log("checkIfCallerIsSelfOrForegoundUser: is self");
+            ok = true;
+        }
+        if (DBG_LOC) log("checkIfCallerIsSelfOrForegoundUser: ret=" + ok);
+        return ok;
+    }
+
     /**
      * Make sure the caller has the READ_PHONE_STATE permission.
      *
@@ -713,6 +771,10 @@
         Log.d(LOG_TAG, "[PhoneIntfMgr] " + msg);
     }
 
+    private void loge(String msg) {
+        Log.e(LOG_TAG, "[PhoneIntfMgr] " + msg);
+    }
+
     public int getActivePhoneType() {
         return mPhone.getPhoneType();
     }
diff --git a/src/com/android/phone/PhoneUtils.java b/src/com/android/phone/PhoneUtils.java
index 616bd40..b71ae35 100644
--- a/src/com/android/phone/PhoneUtils.java
+++ b/src/com/android/phone/PhoneUtils.java
@@ -19,6 +19,7 @@
 import android.app.AlertDialog;
 import android.app.Dialog;
 import android.app.ProgressDialog;
+import android.bluetooth.IBluetoothHeadsetPhone;
 import android.content.ActivityNotFoundException;
 import android.content.ComponentName;
 import android.content.Context;
@@ -27,6 +28,7 @@
 import android.content.ServiceConnection;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
+import android.content.res.Configuration;
 import android.graphics.drawable.Drawable;
 import android.media.AudioManager;
 import android.net.Uri;
@@ -75,7 +77,7 @@
  */
 public class PhoneUtils {
     private static final String LOG_TAG = "PhoneUtils";
-    private static final boolean DBG = (PhoneApp.DBG_LEVEL >= 2);
+    private static final boolean DBG = (PhoneGlobals.DBG_LEVEL >= 2);
 
     // Do not check in with VDBG = true, since that may write PII to the system log.
     private static final boolean VDBG = false;
@@ -244,7 +246,7 @@
      */
     /* package */ static boolean answerCall(Call ringing) {
         log("answerCall(" + ringing + ")...");
-        final PhoneApp app = PhoneApp.getInstance();
+        final PhoneGlobals app = PhoneGlobals.getInstance();
 
         // If the ringer is currently ringing and/or vibrating, stop it
         // right now (before actually answering the call.)
@@ -253,7 +255,7 @@
         final Phone phone = ringing.getPhone();
         final boolean phoneIsCdma = (phone.getPhoneType() == PhoneConstants.PHONE_TYPE_CDMA);
         boolean answered = false;
-        BluetoothHandsfree bluetoothHandsfree = null;
+        IBluetoothHeadsetPhone btPhone = null;
 
         if (phoneIsCdma) {
             // Stop any signalInfo tone being played when a Call waiting gets answered
@@ -283,14 +285,18 @@
                         // drops off
                         app.cdmaPhoneCallState.setAddCallMenuStateAfterCallWaiting(true);
 
-                        // If a BluetoothHandsfree is valid we need to set the second call state
+                        // If a BluetoothPhoneService is valid we need to set the second call state
                         // so that the Bluetooth client can update the Call state correctly when
                         // a call waiting is answered from the Phone.
-                        bluetoothHandsfree = app.getBluetoothHandsfree();
-                        if (bluetoothHandsfree != null) {
-                            bluetoothHandsfree.cdmaSetSecondCallState(true);
+                        btPhone = app.getBluetoothPhoneService();
+                        if (btPhone != null) {
+                            try {
+                                btPhone.cdmaSetSecondCallState(true);
+                            } catch (RemoteException e) {
+                                Log.e(LOG_TAG, Log.getStackTraceString(new Throwable()));
+                            }
                         }
-                    }
+                  }
                 }
 
                 final boolean isRealIncomingCall = isRealIncomingCall(ringing.getState());
@@ -316,7 +322,7 @@
                 // - we did not activate speaker by ourselves during the process above, and
                 // - Bluetooth headset is not in use.
                 if (isRealIncomingCall && !speakerActivated && isSpeakerOn(app)
-                        && !(bluetoothHandsfree != null && bluetoothHandsfree.isAudioOn())) {
+                        && !app.isBluetoothHeadsetAudioOn()) {
                     // This is not an error but might cause users' confusion. Add log just in case.
                     Log.i(LOG_TAG, "Forcing speaker off due to new incoming call...");
                     turnOnSpeaker(app, false, true);
@@ -325,11 +331,15 @@
                 Log.w(LOG_TAG, "answerCall: caught " + ex, ex);
 
                 if (phoneIsCdma) {
-                    // restore the cdmaPhoneCallState and bthf.cdmaSetSecondCallState:
+                    // restore the cdmaPhoneCallState and btPhone.cdmaSetSecondCallState:
                     app.cdmaPhoneCallState.setCurrentCallState(
                             app.cdmaPhoneCallState.getPreviousCallState());
-                    if (bluetoothHandsfree != null) {
-                        bluetoothHandsfree.cdmaSetSecondCallState(false);
+                    if (btPhone != null) {
+                        try {
+                            btPhone.cdmaSetSecondCallState(false);
+                        } catch (RemoteException e) {
+                            Log.e(LOG_TAG, Log.getStackTraceString(new Throwable()));
+                        }
                     }
                 }
             }
@@ -398,7 +408,7 @@
                 // For Call waiting we DO NOT call the conventional hangup(call) function
                 // as in CDMA we just want to hangup the Call waiting connection.
                 log("hangupRingingCall(): CDMA-specific call-waiting hangup");
-                final CallNotifier notifier = PhoneApp.getInstance().notifier;
+                final CallNotifier notifier = PhoneGlobals.getInstance().notifier;
                 notifier.sendCdmaCallWaitingReject();
                 return true;
             } else {
@@ -464,7 +474,7 @@
      */
     static boolean hangup(Call call) {
         try {
-            CallManager cm = PhoneApp.getInstance().mCM;
+            CallManager cm = PhoneGlobals.getInstance().mCM;
 
             if (call.getState() == Call.State.ACTIVE && cm.hasActiveBgCall()) {
                 // handle foreground call hangup while there is background call
@@ -560,7 +570,7 @@
      * </pre>
      * @param app The phone instance.
      */
-    private static void updateCdmaCallStateOnNewOutgoingCall(PhoneApp app) {
+    private static void updateCdmaCallStateOnNewOutgoingCall(PhoneGlobals app) {
         if (app.cdmaPhoneCallState.getCurrentCallState() ==
             CdmaPhoneCallState.PhoneCallState.IDLE) {
             // This is the first outgoing call. Set the Phone Call State to ACTIVE
@@ -607,7 +617,7 @@
                     + ", GW: " + (gatewayUri != null ? "non-null" : "null")
                     + ", emergency? " + isEmergencyCall);
         }
-        final PhoneApp app = PhoneApp.getInstance();
+        final PhoneGlobals app = PhoneGlobals.getInstance();
 
         boolean useGateway = false;
         if (null != gatewayUri &&
@@ -736,9 +746,8 @@
             final boolean speakerActivated = activateSpeakerIfDocked(phone);
 
             // See also similar logic in answerCall().
-            final BluetoothHandsfree bluetoothHandsfree = app.getBluetoothHandsfree();
             if (initiallyIdle && !speakerActivated && isSpeakerOn(app)
-                    && !(bluetoothHandsfree != null && bluetoothHandsfree.isAudioOn())) {
+                    && !app.isBluetoothHeadsetAudioOn()) {
                 // This is not an error but might cause users' confusion. Add log just in case.
                 Log.i(LOG_TAG, "Forcing speaker off when initiating a new outgoing call...");
                 PhoneUtils.turnOnSpeaker(app, false, true);
@@ -790,7 +799,7 @@
     static void switchHoldingAndActive(Call heldCall) {
         log("switchHoldingAndActive()...");
         try {
-            CallManager cm = PhoneApp.getInstance().mCM;
+            CallManager cm = PhoneGlobals.getInstance().mCM;
             if (heldCall.isIdle()) {
                 // no heldCall, so it is to hold active call
                 cm.switchHoldingAndActive(cm.getFgPhone().getBackgroundCall());
@@ -809,7 +818,7 @@
      * foreground call.
      */
     static Boolean restoreMuteState() {
-        Phone phone = PhoneApp.getInstance().mCM.getFgPhone();
+        Phone phone = PhoneGlobals.getInstance().mCM.getFgPhone();
 
         //get the earliest connection
         Connection c = phone.getForegroundCall().getEarliestConnection();
@@ -846,14 +855,14 @@
     }
 
     static void mergeCalls() {
-        mergeCalls(PhoneApp.getInstance().mCM);
+        mergeCalls(PhoneGlobals.getInstance().mCM);
     }
 
     static void mergeCalls(CallManager cm) {
         int phoneType = cm.getFgPhone().getPhoneType();
         if (phoneType == PhoneConstants.PHONE_TYPE_CDMA) {
             log("mergeCalls(): CDMA...");
-            PhoneApp app = PhoneApp.getInstance();
+            PhoneGlobals app = PhoneGlobals.getInstance();
             if (app.cdmaPhoneCallState.getCurrentCallState()
                     == CdmaPhoneCallState.PhoneCallState.THRWAY_ACTIVE) {
                 // Set the Phone Call State to conference
@@ -1000,7 +1009,7 @@
     static void displayMMIComplete(final Phone phone, Context context, final MmiCode mmiCode,
             Message dismissCallbackMessage,
             AlertDialog previousAlert) {
-        final PhoneApp app = PhoneApp.getInstance();
+        final PhoneGlobals app = PhoneGlobals.getInstance();
         CharSequence text;
         int title = 0;  // title for the progress dialog, if needed.
         MmiCode.State state = mmiCode.getState();
@@ -1297,7 +1306,7 @@
             return actualNumberToDial;
         }
 
-        return getNumberFromIntent(PhoneApp.getInstance(), intent);
+        return getNumberFromIntent(PhoneGlobals.getInstance(), intent);
     }
 
     /**
@@ -1790,7 +1799,7 @@
         // you're in a 3-way call, all we can do is display the "generic"
         // state of the UI.)  So as far as the in-call UI is concerned,
         // Conference corresponds to generic display.
-        final PhoneApp app = PhoneApp.getInstance();
+        final PhoneGlobals app = PhoneGlobals.getInstance();
         int phoneType = call.getPhone().getPhoneType();
         if (phoneType == PhoneConstants.PHONE_TYPE_CDMA) {
             CdmaPhoneCallState.PhoneCallState state = app.cdmaPhoneCallState.getCurrentCallState();
@@ -1832,7 +1841,7 @@
      * This is just a wrapper around the ACTION_DIAL intent.
      */
     /* package */ static boolean startNewCall(final CallManager cm) {
-        final PhoneApp app = PhoneApp.getInstance();
+        final PhoneGlobals app = PhoneGlobals.getInstance();
 
         // Sanity-check that this is OK given the current state of the phone.
         if (!okToAddCall(cm)) {
@@ -1878,7 +1887,7 @@
      */
     /* package */ static void turnOnSpeaker(Context context, boolean flag, boolean store) {
         if (DBG) log("turnOnSpeaker(flag=" + flag + ", store=" + store + ")...");
-        final PhoneApp app = PhoneApp.getInstance();
+        final PhoneGlobals app = PhoneGlobals.getInstance();
 
         AudioManager audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
         audioManager.setSpeakerphoneOn(flag);
@@ -1986,7 +1995,7 @@
      *
      */
     static void setMute(boolean muted) {
-        CallManager cm = PhoneApp.getInstance().mCM;
+        CallManager cm = PhoneGlobals.getInstance().mCM;
 
         // make the call to mute the audio
         setMuteInternal(cm.getFgPhone(), muted);
@@ -2005,7 +2014,7 @@
      * Internally used muting function.
      */
     private static void setMuteInternal(Phone phone, boolean muted) {
-        final PhoneApp app = PhoneApp.getInstance();
+        final PhoneGlobals app = PhoneGlobals.getInstance();
         Context context = phone.getContext();
         boolean routeToAudioManager =
             context.getResources().getBoolean(R.bool.send_mic_mute_to_AudioManager);
@@ -2026,7 +2035,7 @@
      * foreground call
      */
     static boolean getMute() {
-        final PhoneApp app = PhoneApp.getInstance();
+        final PhoneGlobals app = PhoneGlobals.getInstance();
 
         boolean routeToAudioManager =
             app.getResources().getBoolean(R.bool.send_mic_mute_to_AudioManager);
@@ -2040,7 +2049,7 @@
     }
 
     /* package */ static void setAudioMode() {
-        setAudioMode(PhoneApp.getInstance().mCM);
+        setAudioMode(PhoneGlobals.getInstance().mCM);
     }
 
     /**
@@ -2049,7 +2058,7 @@
     /* package */ static void setAudioMode(CallManager cm) {
         if (DBG) Log.d(LOG_TAG, "setAudioMode()..." + cm.getState());
 
-        Context context = PhoneApp.getInstance();
+        Context context = PhoneGlobals.getInstance();
         AudioManager audioManager = (AudioManager)
                 context.getSystemService(Context.AUDIO_SERVICE);
         int modeBefore = audioManager.getMode();
@@ -2087,7 +2096,7 @@
      */
     /* package */ static boolean handleHeadsetHook(Phone phone, KeyEvent event) {
         if (DBG) log("handleHeadsetHook()..." + event.getAction() + " " + event.getRepeatCount());
-        final PhoneApp app = PhoneApp.getInstance();
+        final PhoneGlobals app = PhoneGlobals.getInstance();
 
         // If the phone is totally idle, we ignore HEADSETHOOK events
         // (and instead let them fall through to the media player.)
@@ -2140,7 +2149,7 @@
                 Connection c = phone.getForegroundCall().getLatestConnection();
                 // If it is NOT an emg #, toggle the mute state. Otherwise, ignore the hook.
                 if (c != null && !PhoneNumberUtils.isLocalEmergencyNumber(c.getAddress(),
-                                                                          PhoneApp.getInstance())) {
+                                                                          PhoneGlobals.getInstance())) {
                     if (getMute()) {
                         if (DBG) log("handleHeadsetHook: UNmuting...");
                         setMute(false);
@@ -2212,7 +2221,7 @@
         if (phoneType == PhoneConstants.PHONE_TYPE_CDMA) {
             // CDMA: "Swap" is enabled only when the phone reaches a *generic*.
             // state by either accepting a Call Waiting or by merging two calls
-            PhoneApp app = PhoneApp.getInstance();
+            PhoneGlobals app = PhoneGlobals.getInstance();
             return (app.cdmaPhoneCallState.getCurrentCallState()
                     == CdmaPhoneCallState.PhoneCallState.CONF_CALL);
         } else if ((phoneType == PhoneConstants.PHONE_TYPE_GSM)
@@ -2238,7 +2247,7 @@
         int phoneType = cm.getFgPhone().getPhoneType();
         if (phoneType == PhoneConstants.PHONE_TYPE_CDMA) {
             // CDMA: "Merge" is enabled only when the user is in a 3Way call.
-            PhoneApp app = PhoneApp.getInstance();
+            PhoneGlobals app = PhoneGlobals.getInstance();
             return ((app.cdmaPhoneCallState.getCurrentCallState()
                     == CdmaPhoneCallState.PhoneCallState.THRWAY_ACTIVE)
                     && !app.cdmaPhoneCallState.IsThreeWayCallOrigStateDialing());
@@ -2271,7 +2280,7 @@
            // CDMA: "Add call" button is only enabled when:
            // - ForegroundCall is in ACTIVE state
            // - After 30 seconds of user Ignoring/Missing a Call Waiting call.
-            PhoneApp app = PhoneApp.getInstance();
+            PhoneGlobals app = PhoneGlobals.getInstance();
             return ((fgCallState == Call.State.ACTIVE)
                     && (app.cdmaPhoneCallState.getAddCallMenuStateAfterCallWaiting()));
         } else if ((phoneType == PhoneConstants.PHONE_TYPE_GSM)
@@ -2518,12 +2527,11 @@
         if (DBG) log("activateSpeakerIfDocked()...");
 
         boolean activated = false;
-        if (PhoneApp.mDockState != Intent.EXTRA_DOCK_STATE_UNDOCKED) {
+        if (PhoneGlobals.mDockState != Intent.EXTRA_DOCK_STATE_UNDOCKED) {
             if (DBG) log("activateSpeakerIfDocked(): In a dock -> may need to turn on speaker.");
-            PhoneApp app = PhoneApp.getInstance();
-            BluetoothHandsfree bthf = app.getBluetoothHandsfree();
+            PhoneGlobals app = PhoneGlobals.getInstance();
 
-            if (!app.isHeadsetPlugged() && !(bthf != null && bthf.isAudioOn())) {
+            if (!app.isHeadsetPlugged() && !app.isBluetoothHeadsetAudioOn()) {
                 turnOnSpeaker(phone.getContext(), true, true);
                 activated = true;
             }
@@ -2595,12 +2603,12 @@
      * meaning the call is the first real incoming call the phone is having.
      */
     public static boolean isRealIncomingCall(Call.State state) {
-        return (state == Call.State.INCOMING && !PhoneApp.getInstance().mCM.hasActiveFgCall());
+        return (state == Call.State.INCOMING && !PhoneGlobals.getInstance().mCM.hasActiveFgCall());
     }
 
     private static boolean sVoipSupported = false;
     static {
-        PhoneApp app = PhoneApp.getInstance();
+        PhoneGlobals app = PhoneGlobals.getInstance();
         sVoipSupported = SipManager.isVoipSupported(app)
                 && app.getResources().getBoolean(com.android.internal.R.bool.config_built_in_sip_phone)
                 && app.getResources().getBoolean(com.android.internal.R.bool.config_voice_capable);
@@ -2661,7 +2669,7 @@
     //
 
     /* package */ static void dumpCallState(Phone phone) {
-        PhoneApp app = PhoneApp.getInstance();
+        PhoneGlobals app = PhoneGlobals.getInstance();
         Log.d(LOG_TAG, "dumpCallState():");
         Log.d(LOG_TAG, "- Phone: " + phone + ", name = " + phone.getPhoneName()
               + ", state = " + phone.getState());
@@ -2733,7 +2741,7 @@
 
     static void dumpCallManager() {
         Call call;
-        CallManager cm = PhoneApp.getInstance().mCM;
+        CallManager cm = PhoneGlobals.getInstance().mCM;
         StringBuilder b = new StringBuilder(128);
 
 
@@ -2795,4 +2803,12 @@
 
         Log.d(LOG_TAG, "############## END dumpCallManager() ###############");
     }
+
+    /**
+     * @return if the context is in landscape orientation.
+     */
+    public static boolean isLandscape(Context context) {
+        return context.getResources().getConfiguration().orientation
+                == Configuration.ORIENTATION_LANDSCAPE;
+    }
 }
diff --git a/src/com/android/phone/Profiler.java b/src/com/android/phone/Profiler.java
index 186d126..234073c 100644
--- a/src/com/android/phone/Profiler.java
+++ b/src/com/android/phone/Profiler.java
@@ -26,7 +26,7 @@
  * Profiling utilities for the Phone app.
  */
 public class Profiler {
-    private static final String LOG_TAG = PhoneApp.LOG_TAG;
+    private static final String LOG_TAG = PhoneGlobals.LOG_TAG;
 
     // Let the compiler optimize all this code out unless we're actively
     // doing profiling runs.
diff --git a/src/com/android/phone/RespondViaSmsManager.java b/src/com/android/phone/RespondViaSmsManager.java
index bc2ee7b..003c56f 100644
--- a/src/com/android/phone/RespondViaSmsManager.java
+++ b/src/com/android/phone/RespondViaSmsManager.java
@@ -49,12 +49,13 @@
 
 /**
  * Helper class to manage the "Respond via SMS" feature for incoming calls.
+ *
  * @see InCallScreen.internalRespondViaSms()
  */
 public class RespondViaSmsManager {
     private static final String TAG = "RespondViaSmsManager";
     private static final boolean DBG =
-            (PhoneApp.DBG_LEVEL >= 1) && (SystemProperties.getInt("ro.debuggable", 0) == 1);
+            (PhoneGlobals.DBG_LEVEL >= 1) && (SystemProperties.getInt("ro.debuggable", 0) == 1);
     // Do not check in with VDBG = true, since that may write PII to the system log.
     private static final boolean VDBG = false;
 
@@ -118,6 +119,13 @@
     public void showRespondViaSmsPopup(Call ringingCall) {
         if (DBG) log("showRespondViaSmsPopup()...");
 
+        // Very quick succession of clicks can cause this to run twice.
+        // Stop here to avoid creating more than one popup.
+        if (isShowingPopup()) {
+            if (DBG) log("Skip showing popup when one is already shown.");
+            return;
+        }
+
         ListView lv = new ListView(mInCallScreen);
 
         // Refresh the array of "canned responses".
@@ -259,10 +267,10 @@
 
             dismissPopup();
 
-            final PhoneConstants.State state = PhoneApp.getInstance().mCM.getState();
+            final PhoneConstants.State state = PhoneGlobals.getInstance().mCM.getState();
             if (state == PhoneConstants.State.IDLE) {
                 // There's no other phone call to interact. Exit the entire in-call screen.
-                PhoneApp.getInstance().dismissCallScreen();
+                PhoneGlobals.getInstance().dismissCallScreen();
             } else {
                 // The user is still in the middle of other phone calls, so we should keep the
                 // in-call screen.
@@ -288,11 +296,11 @@
 
             dismissPopup();
 
-            final PhoneConstants.State state = PhoneApp.getInstance().mCM.getState();
+            final PhoneConstants.State state = PhoneGlobals.getInstance().mCM.getState();
             if (state == PhoneConstants.State.IDLE) {
                 // This means the incoming call is already hung up when the user chooses not to
                 // use "Respond via SMS" feature. Let's just exit the whole in-call screen.
-                PhoneApp.getInstance().dismissCallScreen();
+                PhoneGlobals.getInstance().dismissCallScreen();
             } else {
 
                 // If the user cancels the popup, this presumably means that
@@ -303,7 +311,7 @@
                 // call UI.
 
                 // This will have no effect if the incoming call isn't still ringing.
-                PhoneApp.getInstance().notifier.restartRinger();
+                PhoneGlobals.getInstance().notifier.restartRinger();
 
                 // We hid the GlowPadView widget way back in
                 // InCallTouchUi.onTrigger(), when the user first selected
diff --git a/src/com/android/phone/Ringer.java b/src/com/android/phone/Ringer.java
index edbcdfa..e97716f 100644
--- a/src/com/android/phone/Ringer.java
+++ b/src/com/android/phone/Ringer.java
@@ -41,7 +41,7 @@
 public class Ringer {
     private static final String LOG_TAG = "Ringer";
     private static final boolean DBG =
-            (PhoneApp.DBG_LEVEL >= 1) && (SystemProperties.getInt("ro.debuggable", 0) == 1);
+            (PhoneGlobals.DBG_LEVEL >= 1) && (SystemProperties.getInt("ro.debuggable", 0) == 1);
 
     private static final int PLAY_RING_ONCE = 1;
     private static final int STOP_RING = 3;
@@ -149,7 +149,7 @@
 
         synchronized (this) {
             try {
-                if (PhoneApp.getInstance().showBluetoothIndication()) {
+                if (PhoneGlobals.getInstance().showBluetoothIndication()) {
                     mPowerManager.setAttentionLight(true, 0x000000ff);
                 } else {
                     mPowerManager.setAttentionLight(true, 0x00ffffff);
diff --git a/src/com/android/phone/SipBroadcastReceiver.java b/src/com/android/phone/SipBroadcastReceiver.java
index 0717c72..c33c5e1 100644
--- a/src/com/android/phone/SipBroadcastReceiver.java
+++ b/src/com/android/phone/SipBroadcastReceiver.java
@@ -91,7 +91,7 @@
     }
 
     private void takeCall(Intent intent) {
-        Context phoneContext = PhoneApp.getInstance();
+        Context phoneContext = PhoneGlobals.getInstance();
         try {
             SipAudioCall sipAudioCall = SipManager.newInstance(phoneContext)
                     .takeAudioCall(intent, null);
@@ -107,7 +107,7 @@
     }
 
     private void registerAllProfiles() {
-        final Context context = PhoneApp.getInstance();
+        final Context context = PhoneGlobals.getInstance();
         new Thread(new Runnable() {
             public void run() {
                 SipManager sipManager = SipManager.newInstance(context);
diff --git a/src/com/android/phone/SipCallOptionHandler.java b/src/com/android/phone/SipCallOptionHandler.java
index 64d18c5..500f322 100644
--- a/src/com/android/phone/SipCallOptionHandler.java
+++ b/src/com/android/phone/SipCallOptionHandler.java
@@ -64,7 +64,7 @@
         CompoundButton.OnCheckedChangeListener {
     static final String TAG = "SipCallOptionHandler";
     private static final boolean DBG =
-            (PhoneApp.DBG_LEVEL >= 1) && (SystemProperties.getInt("ro.debuggable", 0) == 1);
+            (PhoneGlobals.DBG_LEVEL >= 1) && (SystemProperties.getInt("ro.debuggable", 0) == 1);
 
     static final int DIALOG_SELECT_PHONE_TYPE = 0;
     static final int DIALOG_SELECT_OUTGOING_SIP_PHONE = 1;
@@ -147,7 +147,7 @@
         Uri uri = mIntent.getData();
         String scheme = uri.getScheme();
         mNumber = PhoneNumberUtils.getNumberFromIntent(mIntent, this);
-        boolean isInCellNetwork = PhoneApp.getInstance().phoneMgr.isRadioOn();
+        boolean isInCellNetwork = PhoneGlobals.getInstance().phoneMgr.isRadioOn();
         boolean isKnownCallScheme = Constants.SCHEME_TEL.equals(scheme)
                 || Constants.SCHEME_SIP.equals(scheme);
         boolean isRegularCall = Constants.SCHEME_TEL.equals(scheme)
@@ -351,7 +351,7 @@
     }
 
     private void createSipPhoneIfNeeded(SipProfile p) {
-        CallManager cm = PhoneApp.getInstance().mCM;
+        CallManager cm = PhoneGlobals.getInstance().mCM;
         if (PhoneUtils.getSipPhoneFromUri(cm, p.getUriString()) != null) return;
 
         // Create the phone since we can not find it in CallManager
@@ -392,7 +392,7 @@
                     return;
                 } else {
                     // Woo hoo -- it's finally OK to initiate the outgoing call!
-                    PhoneApp.getInstance().callController.placeCall(mIntent);
+                    PhoneGlobals.getInstance().callController.placeCall(mIntent);
                 }
                 finish();
             }
diff --git a/src/com/android/phone/SipUtil.java b/src/com/android/phone/SipUtil.java
index 85a3110..a901d58 100644
--- a/src/com/android/phone/SipUtil.java
+++ b/src/com/android/phone/SipUtil.java
@@ -26,7 +26,7 @@
     }
 
     public static PendingIntent createIncomingCallPendingIntent() {
-        Context phoneContext = PhoneApp.getInstance();
+        Context phoneContext = PhoneGlobals.getInstance();
         Intent intent = new Intent(phoneContext, SipBroadcastReceiver.class);
         intent.setAction(SipManager.ACTION_SIP_INCOMING_CALL);
         return PendingIntent.getBroadcast(phoneContext, 0, intent,
diff --git a/src/com/android/phone/SpecialCharSequenceMgr.java b/src/com/android/phone/SpecialCharSequenceMgr.java
index 0bda10a..a61b378 100644
--- a/src/com/android/phone/SpecialCharSequenceMgr.java
+++ b/src/com/android/phone/SpecialCharSequenceMgr.java
@@ -50,7 +50,7 @@
  * unify these two classes (in the framework? in a common shared library?)
  */
 public class SpecialCharSequenceMgr {
-    private static final String TAG = PhoneApp.LOG_TAG;
+    private static final String TAG = PhoneGlobals.LOG_TAG;
     private static final boolean DBG = false;
 
     private static final String MMI_IMEI_DISPLAY = "*#06#";
@@ -164,7 +164,7 @@
         // input.  We want to make sure that sim card contacts are NOT
         // exposed unless the phone is unlocked, and this code can be
         // accessed from the emergency dialer.
-        if (PhoneApp.getInstance().getKeyguardManager().inKeyguardRestrictedInputMode()) {
+        if (PhoneGlobals.getInstance().getKeyguardManager().inKeyguardRestrictedInputMode()) {
             return false;
         }
 
@@ -178,7 +178,7 @@
                                     "com.android.phone.SimContacts");
                 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                 intent.putExtra("index", index);
-                PhoneApp.getInstance().startActivity(intent);
+                PhoneGlobals.getInstance().startActivity(intent);
 
                 return true;
             } catch (NumberFormatException ex) {}
@@ -193,7 +193,7 @@
         // if a dialstring is an MMI code.
         if ((input.startsWith("**04") || input.startsWith("**05"))
                 && input.endsWith("#")) {
-            PhoneApp app = PhoneApp.getInstance();
+            PhoneGlobals app = PhoneGlobals.getInstance();
             boolean isMMIHandled = app.phone.handlePinMmi(input);
 
             // if the PUK code is recognized then indicate to the
@@ -222,7 +222,7 @@
     static private void showDeviceIdPanel(Context context) {
         if (DBG) log("showDeviceIdPanel()...");
 
-        Phone phone = PhoneApp.getPhone();
+        Phone phone = PhoneGlobals.getPhone();
         int labelId = TelephonyCapabilities.getDeviceIdLabel(phone);
         String deviceId = phone.getDeviceId();
 
diff --git a/src/com/android/phone/TimeConsumingPreferenceActivity.java b/src/com/android/phone/TimeConsumingPreferenceActivity.java
index 89275e7..19c4dda 100644
--- a/src/com/android/phone/TimeConsumingPreferenceActivity.java
+++ b/src/com/android/phone/TimeConsumingPreferenceActivity.java
@@ -24,7 +24,7 @@
                         implements TimeConsumingPreferenceListener,
                         DialogInterface.OnCancelListener {
     private static final String LOG_TAG = "TimeConsumingPreferenceActivity";
-    private final boolean DBG = (PhoneApp.DBG_LEVEL >= 2);
+    private final boolean DBG = (PhoneGlobals.DBG_LEVEL >= 2);
 
     private class DismissOnClickListener implements DialogInterface.OnClickListener {
         @Override
diff --git a/src/com/android/phone/Use2GOnlyCheckBoxPreference.java b/src/com/android/phone/Use2GOnlyCheckBoxPreference.java
index a25882e..4da238b 100644
--- a/src/com/android/phone/Use2GOnlyCheckBoxPreference.java
+++ b/src/com/android/phone/Use2GOnlyCheckBoxPreference.java
@@ -42,7 +42,7 @@
 
     public Use2GOnlyCheckBoxPreference(Context context, AttributeSet attrs, int defStyle) {
         super(context, attrs, defStyle);
-        mPhone = PhoneApp.getPhone();
+        mPhone = PhoneGlobals.getPhone();
         mHandler = new MyHandler();
         mPhone.getPreferredNetworkType(
                 mHandler.obtainMessage(MyHandler.MESSAGE_GET_PREFERRED_NETWORK_TYPE));
@@ -54,8 +54,8 @@
 
         int networkType = isChecked() ? Phone.NT_MODE_GSM_ONLY : Phone.NT_MODE_WCDMA_PREF;
         Log.i(LOG_TAG, "set preferred network type="+networkType);
-        android.provider.Settings.Secure.putInt(mPhone.getContext().getContentResolver(),
-                android.provider.Settings.Secure.PREFERRED_NETWORK_MODE, networkType);
+        android.provider.Settings.Global.putInt(mPhone.getContext().getContentResolver(),
+                android.provider.Settings.Global.PREFERRED_NETWORK_MODE, networkType);
         mPhone.setPreferredNetworkType(networkType, mHandler
                 .obtainMessage(MyHandler.MESSAGE_SET_PREFERRED_NETWORK_TYPE));
    }
@@ -89,8 +89,8 @@
                 }
                 Log.i(LOG_TAG, "get preferred network type="+type);
                 setChecked(type == Phone.NT_MODE_GSM_ONLY);
-                android.provider.Settings.Secure.putInt(mPhone.getContext().getContentResolver(),
-                        android.provider.Settings.Secure.PREFERRED_NETWORK_MODE, type);
+                android.provider.Settings.Global.putInt(mPhone.getContext().getContentResolver(),
+                        android.provider.Settings.Global.PREFERRED_NETWORK_MODE, type);
             } else {
                 // Weird state, disable the setting
                 Log.i(LOG_TAG, "get preferred network type, exception="+ar.exception);