Merge "Clear IP configuration on lost network" into honeycomb-LTE
diff --git a/api/current.xml b/api/current.xml
index acea195..4841d01 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -15714,6 +15714,28 @@
  visibility="public"
 >
 </field>
+<field name="Theme_Holo_Light_NoActionBar"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16974064"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="Theme_Holo_Light_NoActionBar_Fullscreen"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16974065"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="Theme_Holo_Light_Panel"
  type="int"
  transient="false"
@@ -114476,6 +114498,28 @@
  visibility="public"
 >
 </field>
+<field name="TYPE_BLUETOOTH"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="7"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TYPE_ETHERNET"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="9"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="TYPE_MOBILE"
  type="int"
  transient="false"
@@ -184515,6 +184559,17 @@
  visibility="public"
 >
 </field>
+<field name="NETWORK_TYPE_HSPAP"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="15"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="NETWORK_TYPE_HSUPA"
  type="int"
  transient="false"
@@ -267731,7 +267786,7 @@
  deprecated="not deprecated"
  visibility="public"
 >
-<parameter name="arg0" type="T">
+<parameter name="t" type="T">
 </parameter>
 </method>
 </interface>
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index b541ec3..eaf9191 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -165,14 +165,12 @@
 
     /**
      * The Default Mobile data connection.  When active, all data traffic
-     * will use this connection by default.  Should not coexist with other
-     * default connections.
+     * will use this connection by default.
      */
     public static final int TYPE_MOBILE      = 0;
     /**
      * The Default WIFI data connection.  When active, all data traffic
-     * will use this connection by default.  Should not coexist with other
-     * default connections.
+     * will use this connection by default.
      */
     public static final int TYPE_WIFI        = 1;
     /**
@@ -208,21 +206,23 @@
     public static final int TYPE_MOBILE_HIPRI = 5;
     /**
      * The Default WiMAX data connection.  When active, all data traffic
-     * will use this connection by default.  Should not coexist with other
-     * default connections.
+     * will use this connection by default.
      */
     public static final int TYPE_WIMAX       = 6;
 
     /**
-     * Bluetooth data connection. This is used for Bluetooth reverse tethering.
-     * @hide
+     * The Default Bluetooth data connection. When active, all data traffic
+     * will use this connection by default.
      */
     public static final int TYPE_BLUETOOTH   = 7;
 
     /** {@hide} */
     public static final int TYPE_DUMMY       = 8;
 
-    /** {@hide} */
+    /**
+     * The Default Ethernet data connection.  When active, all data traffic
+     * will use this connection by default.
+     */
     public static final int TYPE_ETHERNET    = 9;
     /**
      * Over the air Adminstration.
diff --git a/core/java/android/view/ViewConfiguration.java b/core/java/android/view/ViewConfiguration.java
index 739758c..392797c 100644
--- a/core/java/android/view/ViewConfiguration.java
+++ b/core/java/android/view/ViewConfiguration.java
@@ -111,7 +111,21 @@
      * double-tap.
      */
     private static final int DOUBLE_TAP_TIMEOUT = 300;
-    
+
+    /**
+     * Defines the maximum duration in milliseconds between a touch pad
+     * touch and release for a given touch to be considered a tap (click) as
+     * opposed to a hover movement gesture.
+     */
+    private static final int HOVER_TAP_TIMEOUT = 150;
+
+    /**
+     * Defines the maximum distance in pixels that a touch pad touch can move
+     * before being released for it to be considered a tap (click) as opposed
+     * to a hover movement gesture.
+     */
+    private static final int HOVER_TAP_SLOP = 20;
+
     /**
      * Defines the duration in milliseconds we want to display zoom controls in response 
      * to a user panning within an application.
@@ -360,7 +374,7 @@
     public static int getTapTimeout() {
         return TAP_TIMEOUT;
     }
-    
+
     /**
      * @return the duration in milliseconds we will wait to see if a touch event
      * is a jump tap. If the user does not move within this interval, it is
@@ -378,7 +392,27 @@
     public static int getDoubleTapTimeout() {
         return DOUBLE_TAP_TIMEOUT;
     }
-    
+
+    /**
+     * @return the maximum duration in milliseconds between a touch pad
+     * touch and release for a given touch to be considered a tap (click) as
+     * opposed to a hover movement gesture.
+     * @hide
+     */
+    public static int getHoverTapTimeout() {
+        return HOVER_TAP_TIMEOUT;
+    }
+
+    /**
+     * @return the maximum distance in pixels that a touch pad touch can move
+     * before being released for it to be considered a tap (click) as opposed
+     * to a hover movement gesture.
+     * @hide
+     */
+    public static int getHoverTapSlop() {
+        return HOVER_TAP_SLOP;
+    }
+
     /**
      * @return Inset in pixels to look for touchable content when the user touches the edge of the
      *         screen
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 0d34ff6..eeb5b7b 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -6215,7 +6215,7 @@
                     if (hscroll != 0 || vscroll != 0) {
                         final int vdelta = (int) (vscroll * getVerticalScrollFactor());
                         final int hdelta = (int) (hscroll * getHorizontalScrollFactor());
-                        if (pinScrollBy(hdelta, vdelta, true, 0)) {
+                        if (pinScrollBy(hdelta, vdelta, false, 0)) {
                             return true;
                         }
                     }
diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index 0dc0422..682ebc4 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -33,6 +33,7 @@
 import android.telephony.TelephonyManager;
 import android.text.TextUtils;
 import android.util.Log;
+import android.view.View;
 import android.widget.Button;
 
 import java.io.File;
@@ -775,6 +776,16 @@
         setBoolean(LOCKOUT_PERMANENT_KEY, locked);
     }
 
+    public boolean isEmergencyCallCapable() {
+        return mContext.getResources().getBoolean(
+                com.android.internal.R.bool.config_voice_capable);
+    }
+
+    public boolean isPukUnlockScreenEnable() {
+        return mContext.getResources().getBoolean(
+                com.android.internal.R.bool.config_enable_puk_unlock_screen);
+    }
+
     /**
      * @return A formatted string of the next alarm (for showing on the lock screen),
      *   or null if there is no next alarm.
@@ -827,11 +838,22 @@
     }
 
     /**
-     * Sets the text on the emergency button to indicate what action will be taken.
+     * Sets the emergency button visibility based on isEmergencyCallCapable().
+     *
+     * If the emergency button is visible, sets the text on the emergency button
+     * to indicate what action will be taken.
+     *
      * If there's currently a call in progress, the button will take them to the call
      * @param button the button to update
      */
     public void updateEmergencyCallButtonState(Button button) {
+        if (isEmergencyCallCapable()) {
+            button.setVisibility(View.VISIBLE);
+        } else {
+            button.setVisibility(View.GONE);
+            return;
+        }
+
         int newState = TelephonyManager.getDefault().getCallState();
         int textId;
         if (newState == TelephonyManager.CALL_STATE_OFFHOOK) {
diff --git a/core/res/res/layout/keyguard_screen_sim_puk_landscape.xml b/core/res/res/layout/keyguard_screen_sim_puk_landscape.xml
new file mode 100644
index 0000000..d58fb23
--- /dev/null
+++ b/core/res/res/layout/keyguard_screen_sim_puk_landscape.xml
@@ -0,0 +1,182 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+**
+** Copyright 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.
+*/
+-->
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:orientation="vertical"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:background="@android:color/background_dark"
+        >
+
+    <LinearLayout android:id="@+id/topDisplayGroup"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="vertical">
+
+        <!-- header text ('Enter Puk Code') -->
+        <TextView android:id="@+id/headerText"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:gravity="center"
+            android:singleLine="true"
+            android:textAppearance="?android:attr/textAppearanceLarge"/>
+
+        <!-- Carrier info -->
+        <TextView android:id="@+id/carrier"
+            android:layout_width="fill_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginTop="9dip"
+            android:gravity="center"
+            android:singleLine="true"
+            android:ellipsize="marquee"
+            android:textAppearance="?android:attr/textAppearanceMedium"/>
+
+        <LinearLayout
+            android:orientation="horizontal"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content">
+
+            <LinearLayout
+                android:orientation="vertical"
+                android:layout_width="wrap_content"
+                android:layout_height="match_parent"
+                android:layout_marginRight="10dip"
+                android:layout_marginLeft="10dip">
+                <TextView android:id="@+id/enter_puk"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:gravity="center_vertical"
+                    android:text="@android:string/keyguard_password_enter_puk_prompt"
+                    android:textSize="30sp"
+                    android:layout_marginBottom="10dip"/>
+                <TextView android:id="@+id/enter_pin"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:gravity="center_vertical"
+                    android:text="@android:string/keyguard_password_enter_pin_prompt"
+                    android:textSize="30sp"
+                    android:layout_marginTop="10dip"/>
+            </LinearLayout>
+
+            <LinearLayout
+                  android:orientation="vertical"
+                  android:layout_width="wrap_content"
+                  android:layout_weight="1"
+                  android:layout_height="match_parent"
+                  android:paddingRight="0dip"
+                  android:layout_marginRight="10dip"
+                  android:layout_marginLeft="10dip">
+
+                  <LinearLayout
+                      android:layout_width="match_parent"
+                      android:layout_height="wrap_content"
+                      android:orientation="horizontal"
+                      android:layout_marginRight="6dip"
+                      android:layout_marginLeft="6dip"
+                      android:gravity="center_vertical"
+                      android:background="@android:drawable/edit_text">
+
+                      <!-- displays dots as user enters puk -->
+                      <TextView android:id="@+id/pukDisplay"
+                          android:layout_width="0dip"
+                          android:layout_height="wrap_content"
+                          android:layout_weight="1"
+                          android:maxLines="1"
+                          android:textAppearance="?android:attr/textAppearanceLargeInverse"
+                          android:textStyle="bold"
+                          android:inputType="textPassword"
+                      />
+
+                      <ImageButton android:id="@+id/pukDel"
+                          android:src="@android:drawable/ic_input_delete"
+                          android:layout_width="wrap_content"
+                          android:layout_height="wrap_content"
+                          android:layout_marginRight="-3dip"
+                          android:layout_marginBottom="-3dip"
+                      />
+                  </LinearLayout>
+
+
+                  <LinearLayout
+                      android:layout_width="match_parent"
+                      android:layout_height="wrap_content"
+                      android:orientation="horizontal"
+                      android:layout_marginRight="6dip"
+                      android:layout_marginLeft="6dip"
+                      android:gravity="center_vertical"
+                      android:background="@android:drawable/edit_text">
+
+                      <!-- displays dots as user enters new pin -->
+                      <TextView android:id="@+id/pinDisplay"
+                          android:layout_width="0dip"
+                          android:layout_height="wrap_content"
+                          android:layout_weight="1"
+                          android:maxLines="1"
+                          android:textAppearance="?android:attr/textAppearanceLargeInverse"
+                          android:textStyle="bold"
+                          android:inputType="textPassword"
+                      />
+
+                      <ImageButton android:id="@+id/pinDel"
+                          android:src="@android:drawable/ic_input_delete"
+                          android:layout_width="wrap_content"
+                          android:layout_height="wrap_content"
+                          android:layout_marginRight="-3dip"
+                          android:layout_marginBottom="-3dip"
+                      />
+                  </LinearLayout>
+              </LinearLayout>
+        </LinearLayout>
+    </LinearLayout>
+
+    <LinearLayout
+        android:orientation="horizontal"
+        android:layout_alignParentBottom="true"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_marginBottom="8dip"
+        android:layout_marginLeft="8dip"
+        android:layout_marginRight="8dip">
+
+        <Button android:id="@+id/ok"
+            android:text="@android:string/ok"
+            android:layout_alignParentBottom="true"
+            android:layout_width="0dip"
+            android:layout_height="wrap_content"
+            android:layout_weight="1.0"
+            android:layout_marginBottom="8dip"
+            android:layout_marginRight="8dip"
+            android:textSize="18sp"
+            />
+
+        <Button android:id="@+id/emergencyCall"
+            android:text="@android:string/lockscreen_emergency_call"
+            android:layout_alignParentBottom="true"
+            android:layout_centerHorizontal="true"
+            android:layout_width="0dip"
+            android:layout_height="wrap_content"
+            android:layout_weight="1.0"
+            android:layout_marginBottom="8dip"
+            android:layout_marginLeft="8dip"
+            android:textSize="18sp"
+            android:drawableLeft="@drawable/ic_emergency"
+            android:drawablePadding="8dip"
+        />
+    </LinearLayout>
+
+</RelativeLayout>
diff --git a/core/res/res/layout/keyguard_screen_sim_puk_portrait.xml b/core/res/res/layout/keyguard_screen_sim_puk_portrait.xml
new file mode 100644
index 0000000..5e392ef
--- /dev/null
+++ b/core/res/res/layout/keyguard_screen_sim_puk_portrait.xml
@@ -0,0 +1,185 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+**
+** Copyright 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.
+*/
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="vertical"
+    android:background="@android:color/background_dark"
+    android:gravity="center_horizontal">
+
+    <LinearLayout android:id="@+id/topDisplayGroup"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="vertical">
+
+        <!-- header text ('Enter Puk Code') -->
+        <TextView android:id="@+id/headerText"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:gravity="center"
+            android:singleLine="true"
+            android:textAppearance="?android:attr/textAppearanceLarge"/>
+
+        <!-- Carrier info -->
+        <TextView android:id="@+id/carrier"
+            android:layout_width="fill_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginTop="9dip"
+            android:gravity="center"
+            android:singleLine="true"
+            android:ellipsize="marquee"
+            android:textAppearance="?android:attr/textAppearanceMedium"/>
+
+        <LinearLayout
+            android:orientation="horizontal"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content">
+
+            <LinearLayout
+                android:orientation="vertical"
+                android:layout_width="wrap_content"
+                android:layout_height="match_parent"
+                android:layout_marginRight="10dip"
+                android:layout_marginLeft="10dip">
+                <TextView android:id="@+id/enter_puk"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:gravity="center_vertical"
+                    android:text="@android:string/keyguard_password_enter_puk_prompt"
+                    android:textSize="30sp"
+                    android:layout_marginBottom="10dip"/>
+                <TextView android:id="@+id/enter_pin"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:gravity="center_vertical"
+                    android:text="@android:string/keyguard_password_enter_pin_prompt"
+                    android:textSize="30sp"
+                    android:layout_marginTop="10dip"/>
+            </LinearLayout>
+
+            <LinearLayout
+                  android:orientation="vertical"
+                  android:layout_width="wrap_content"
+                  android:layout_weight="1"
+                  android:layout_height="match_parent"
+                  android:paddingRight="0dip"
+                  android:layout_marginRight="10dip"
+                  android:layout_marginLeft="10dip">
+
+                  <LinearLayout
+                      android:layout_width="match_parent"
+                      android:layout_height="wrap_content"
+                      android:orientation="horizontal"
+                      android:layout_marginRight="6dip"
+                      android:layout_marginLeft="6dip"
+                      android:gravity="center_vertical"
+                      android:background="@android:drawable/edit_text">
+
+                      <!-- displays dots as user enters puk -->
+                      <TextView android:id="@+id/pukDisplay"
+                          android:layout_width="0dip"
+                          android:layout_height="wrap_content"
+                          android:layout_weight="1"
+                          android:maxLines="1"
+                          android:textAppearance="?android:attr/textAppearanceLargeInverse"
+                          android:textStyle="bold"
+                          android:inputType="textPassword"
+                      />
+
+                      <ImageButton android:id="@+id/pukDel"
+                          android:src="@android:drawable/ic_input_delete"
+                          android:layout_width="wrap_content"
+                          android:layout_height="wrap_content"
+                          android:layout_marginRight="-3dip"
+                          android:layout_marginBottom="-3dip"
+                      />
+                  </LinearLayout>
+
+
+                  <LinearLayout
+                      android:layout_width="match_parent"
+                      android:layout_height="wrap_content"
+                      android:orientation="horizontal"
+                      android:layout_marginRight="6dip"
+                      android:layout_marginLeft="6dip"
+                      android:gravity="center_vertical"
+                      android:background="@android:drawable/edit_text">
+
+                      <!-- displays dots as user enters new pin -->
+                      <TextView android:id="@+id/pinDisplay"
+                          android:layout_width="0dip"
+                          android:layout_height="wrap_content"
+                          android:layout_weight="1"
+                          android:maxLines="1"
+                          android:textAppearance="?android:attr/textAppearanceLargeInverse"
+                          android:textStyle="bold"
+                          android:inputType="textPassword"
+                      />
+
+                      <ImageButton android:id="@+id/pinDel"
+                          android:src="@android:drawable/ic_input_delete"
+                          android:layout_width="wrap_content"
+                          android:layout_height="wrap_content"
+                          android:layout_marginRight="-3dip"
+                          android:layout_marginBottom="-3dip"
+                      />
+                  </LinearLayout>
+              </LinearLayout>
+        </LinearLayout>
+    </LinearLayout>
+
+    <include
+        android:id="@+id/keyPad"
+        layout="@android:layout/twelve_key_entry"
+        android:layout_width="fill_parent"
+        android:layout_height="wrap_content"
+        android:layout_below="@id/topDisplayGroup"
+        android:layout_marginTop="10dip"
+    />
+
+    <!-- spacer below keypad -->
+    <View
+        android:id="@+id/spacerBottom"
+        android:layout_width="match_parent"
+        android:layout_height="1dip"
+        android:layout_marginTop="6dip"
+        android:layout_above="@id/emergencyCall"
+        android:background="@android:drawable/divider_horizontal_dark"
+    />
+
+    <!-- The emergency button should take the rest of the space and be centered vertically -->
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="0dip"
+        android:layout_weight="1"
+        android:gravity="center"
+        android:orientation="vertical">
+
+        <!-- emergency call button -->
+        <Button
+            android:id="@+id/emergencyCall"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:drawableLeft="@android:drawable/ic_emergency"
+            android:drawablePadding="8dip"
+            android:text="@android:string/lockscreen_emergency_call"
+        />
+    </LinearLayout>
+
+</LinearLayout>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 4bcdac1..60f11ce 100755
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -369,6 +369,10 @@
     <!-- Diable lockscreen rotation by default -->
     <bool name="config_enableLockScreenRotation">false</bool>
 
+    <!-- Diable puk unlockscreen by default.
+         If unlock screen is disabled, the puk should be unlocked through Emergency Dialer -->
+    <bool name="config_enable_puk_unlock_screen">false</bool>
+
     <!-- Control the behavior when the user long presses the power button.
             0 - Nothing
             1 - Recent apps dialog
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 85884b1..47b5c60 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -1657,4 +1657,8 @@
   <public type="attr" name="requiresSmallestWidthDp" id="0x01010364" />
   <public type="attr" name="compatibleWidthLimitDp" />
   <public type="attr" name="largestWidthLimitDp" />
+
+  <public type="style" name="Theme.Holo.Light.NoActionBar" />
+  <public type="style" name="Theme.Holo.Light.NoActionBar.Fullscreen" />
+
 </resources>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index f7f2606..20ee8ff 100755
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -87,6 +87,8 @@
     <string name="mismatchPin">The PINs you entered do not match.</string>
     <!-- Displayed when a SIM PIN password is too long or too short. -->
     <string name="invalidPin">Type a PIN that is 4 to 8 numbers.</string>
+    <!-- Displayed when a SIM PUK password is too short. -->
+    <string name="invalidPuk">Type a PUK that is 8 numbers or longer.</string>
     <!-- Displayed to prompt the user to type the PUK password to unlock
          the SIM card. -->
     <string name="needPuk">Your SIM card is PUK-locked. Type the PUK code to unlock it.</string>
@@ -1644,6 +1646,15 @@
          Displayed in one line in a large font.  -->
     <string name="keyguard_password_enter_pin_code">Enter PIN code</string>
 
+    <!-- Instructions telling the user to enter their SIM PUK to unlock the keyguard.
+         Displayed in one line in a large font.  -->
+    <string name="keyguard_password_enter_puk_code">Enter PUK and new PIN code</string>
+
+    <!-- Prompt to enter SIM PUK in Edit Text Box in unlock screen -->
+    <string name="keyguard_password_enter_puk_prompt">PUK code</string>
+    <!-- Prompt to enter New SIM PIN in Edit Text Box in unlock screen -->
+    <string name="keyguard_password_enter_pin_prompt">New Pin Code</string>
+
     <!-- Displayed as hint in passwordEntry EditText on PasswordUnlockScreen [CHAR LIMIT=30]-->
     <string name="keyguard_password_entry_touch_hint"><font size="17">Touch to enter password</font></string>
 
diff --git a/include/ui/Input.h b/include/ui/Input.h
index d603441..074b38f 100644
--- a/include/ui/Input.h
+++ b/include/ui/Input.h
@@ -608,11 +608,6 @@
     // Oldest sample to consider when calculating the velocity.
     static const nsecs_t MAX_AGE = 200 * 1000000; // 200 ms
 
-    // When the total duration of the window of samples being averaged is less
-    // than the window size, the resulting velocity is scaled to reduce the impact
-    // of overestimation in short traces.
-    static const nsecs_t MIN_WINDOW = 100 * 1000000; // 100 ms
-
     // The minimum duration between samples when estimating velocity.
     static const nsecs_t MIN_DURATION = 10 * 1000000; // 10 ms
 
diff --git a/include/utils/RefBase.h b/include/utils/RefBase.h
index f355087..e88cb29 100644
--- a/include/utils/RefBase.h
+++ b/include/utils/RefBase.h
@@ -120,7 +120,14 @@
 protected:
                             RefBase();
     virtual                 ~RefBase();
-    
+
+    // called when the last reference goes away. this is responsible for
+    // calling the destructor. The default implementation just does
+    // "delete this;".
+    // Make sure to never acquire a strong reference from this function. The
+    // same restrictions than for destructors apply.
+    virtual void            destroy() const;
+
     //! Flags for extendObjectLifetime()
     enum {
         OBJECT_LIFETIME_WEAK    = 0x0001,
diff --git a/libs/ui/Input.cpp b/libs/ui/Input.cpp
index 50b75d5..1fc46aa 100644
--- a/libs/ui/Input.cpp
+++ b/libs/ui/Input.cpp
@@ -677,7 +677,6 @@
 
 const uint32_t VelocityTracker::HISTORY_SIZE;
 const nsecs_t VelocityTracker::MAX_AGE;
-const nsecs_t VelocityTracker::MIN_WINDOW;
 const nsecs_t VelocityTracker::MIN_DURATION;
 
 VelocityTracker::VelocityTracker() {
@@ -868,14 +867,6 @@
 
         // Make sure we used at least one sample.
         if (samplesUsed != 0) {
-            // Scale the velocity linearly if the window of samples is small.
-            nsecs_t totalDuration = newestMovement.eventTime - oldestMovement.eventTime;
-            if (totalDuration < MIN_WINDOW) {
-                float scale = float(totalDuration) / float(MIN_WINDOW);
-                accumVx *= scale;
-                accumVy *= scale;
-            }
-
             *outVx = accumVx;
             *outVy = accumVy;
             return true;
diff --git a/libs/utils/RefBase.cpp b/libs/utils/RefBase.cpp
index bb6c125..7de2633 100644
--- a/libs/utils/RefBase.cpp
+++ b/libs/utils/RefBase.cpp
@@ -345,6 +345,10 @@
     const_cast<RefBase*>(this)->onFirstRef();
 }
 
+void RefBase::destroy() const {
+    delete this;
+}
+
 void RefBase::decStrong(const void* id) const
 {
     weakref_impl* const refs = mRefs;
@@ -357,7 +361,7 @@
     if (c == 1) {
         const_cast<RefBase*>(this)->onLastStrongRef(id);
         if ((refs->mFlags&OBJECT_LIFETIME_WEAK) != OBJECT_LIFETIME_WEAK) {
-            delete this;
+            destroy();
         }
     }
     refs->decWeak(id);
@@ -415,7 +419,8 @@
     
     if ((impl->mFlags&OBJECT_LIFETIME_WEAK) != OBJECT_LIFETIME_WEAK) {
         if (impl->mStrong == INITIAL_STRONG_VALUE)
-            delete impl->mBase;
+            if (impl->mBase)
+                impl->mBase->destroy();
         else {
             // LOGV("Freeing refs %p of old RefBase %p\n", this, impl->mBase);
             delete impl;
@@ -423,7 +428,8 @@
     } else {
         impl->mBase->onLastWeakRef(id);
         if ((impl->mFlags&OBJECT_LIFETIME_FOREVER) != OBJECT_LIFETIME_FOREVER) {
-            delete impl->mBase;
+            if (impl->mBase)
+                impl->mBase->destroy();
         }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
index 70a78df..3175a99 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
@@ -446,12 +446,14 @@
     }
 
     boolean isCdmaEri() {
-        final int iconIndex = mServiceState.getCdmaEriIconIndex();
-        if (iconIndex != EriInfo.ROAMING_INDICATOR_OFF) {
-            final int iconMode = mServiceState.getCdmaEriIconMode();
-            if (iconMode == EriInfo.ROAMING_ICON_MODE_NORMAL
-                    || iconMode == EriInfo.ROAMING_ICON_MODE_FLASH) {
-                return true;
+        if (mServiceState != null) {
+            final int iconIndex = mServiceState.getCdmaEriIconIndex();
+            if (iconIndex != EriInfo.ROAMING_INDICATOR_OFF) {
+                final int iconMode = mServiceState.getCdmaEriIconMode();
+                if (iconMode == EriInfo.ROAMING_ICON_MODE_NORMAL
+                        || iconMode == EriInfo.ROAMING_ICON_MODE_FLASH) {
+                    return true;
+                }
             }
         }
         return false;
@@ -854,7 +856,7 @@
         pw.print("  mDataActivity=");
         pw.println(mDataActivity);
         pw.print("  mServiceState=");
-        pw.println(mServiceState.toString());
+        pw.println(mServiceState);
         pw.print("  mNetworkName=");
         pw.println(mNetworkName);
         pw.print("  mNetworkNameDefault=");
diff --git a/policy/src/com/android/internal/policy/impl/KeyguardUpdateMonitor.java b/policy/src/com/android/internal/policy/impl/KeyguardUpdateMonitor.java
index 5ed67a9..72209f6 100644
--- a/policy/src/com/android/internal/policy/impl/KeyguardUpdateMonitor.java
+++ b/policy/src/com/android/internal/policy/impl/KeyguardUpdateMonitor.java
@@ -480,11 +480,11 @@
     }
 
     /**
-     * Report that the user succesfully entered the sim pin so we
+     * Report that the user succesfully entered the sim pin or puk so we
      * have the information earlier than waiting for the intent
      * broadcast from the telephony code.
      */
-    public void reportSimPinUnlocked() {
+    public void reportSimUnlocked() {
         mSimState = IccCard.State.READY;
     }
 
diff --git a/policy/src/com/android/internal/policy/impl/LockPatternKeyguardView.java b/policy/src/com/android/internal/policy/impl/LockPatternKeyguardView.java
index 2fda3aa..874acd0 100644
--- a/policy/src/com/android/internal/policy/impl/LockPatternKeyguardView.java
+++ b/policy/src/com/android/internal/policy/impl/LockPatternKeyguardView.java
@@ -116,6 +116,11 @@
         SimPin,
 
         /**
+         * Unlock by entering a sim puk.
+         */
+        SimPuk,
+
+        /**
          * Unlock by entering an account's login and password.
          */
         Account,
@@ -222,8 +227,10 @@
             public void goToUnlockScreen() {
                 final IccCard.State simState = mUpdateMonitor.getSimState();
                 if (stuckOnLockScreenBecauseSimMissing()
-                         || (simState == IccCard.State.PUK_REQUIRED)){
-                    // stuck on lock screen when sim missing or puk'd
+                         || (simState == IccCard.State.PUK_REQUIRED
+                             && !mLockPatternUtils.isPukUnlockScreenEnable())){
+                    // stuck on lock screen when sim missing or
+                    // puk'd but puk unlock screen is disabled
                     return;
                 }
                 if (!isSecure()) {
@@ -522,8 +529,10 @@
                 secure = mLockPatternUtils.isLockPatternEnabled();
                 break;
             case SimPin:
-                secure = mUpdateMonitor.getSimState() == IccCard.State.PIN_REQUIRED
-                            || mUpdateMonitor.getSimState() == IccCard.State.PUK_REQUIRED;
+                secure = mUpdateMonitor.getSimState() == IccCard.State.PIN_REQUIRED;
+                break;
+            case SimPuk:
+                secure = mUpdateMonitor.getSimState() == IccCard.State.PUK_REQUIRED;
                 break;
             case Account:
                 secure = true;
@@ -592,6 +601,10 @@
 
     View createUnlockScreenFor(UnlockMode unlockMode) {
         View unlockView = null;
+
+        if (DEBUG) Log.d(TAG,
+                "createUnlockScreenFor(" + unlockMode + "): mEnableFallback=" + mEnableFallback);
+
         if (unlockMode == UnlockMode.Pattern) {
             PatternUnlockScreen view = new PatternUnlockScreen(
                     mContext,
@@ -600,10 +613,15 @@
                     mUpdateMonitor,
                     mKeyguardScreenCallback,
                     mUpdateMonitor.getFailedAttempts());
-            if (DEBUG) Log.d(TAG,
-                "createUnlockScreenFor(" + unlockMode + "): mEnableFallback=" + mEnableFallback);
             view.setEnableFallback(mEnableFallback);
             unlockView = view;
+        } else if (unlockMode == UnlockMode.SimPuk) {
+            unlockView = new SimPukUnlockScreen(
+                    mContext,
+                    mConfiguration,
+                    mUpdateMonitor,
+                    mKeyguardScreenCallback,
+                    mLockPatternUtils);
         } else if (unlockMode == UnlockMode.SimPin) {
             unlockView = new SimUnlockScreen(
                     mContext,
@@ -654,7 +672,9 @@
      */
     private Mode getInitialMode() {
         final IccCard.State simState = mUpdateMonitor.getSimState();
-        if (stuckOnLockScreenBecauseSimMissing() || (simState == IccCard.State.PUK_REQUIRED)) {
+        if (stuckOnLockScreenBecauseSimMissing() ||
+                (simState == IccCard.State.PUK_REQUIRED &&
+                        !mLockPatternUtils.isPukUnlockScreenEnable())) {
             return Mode.LockScreen;
         } else {
             // Show LockScreen first for any screen other than Pattern unlock.
@@ -676,8 +696,10 @@
     private UnlockMode getUnlockMode() {
         final IccCard.State simState = mUpdateMonitor.getSimState();
         UnlockMode currentMode;
-        if (simState == IccCard.State.PIN_REQUIRED || simState == IccCard.State.PUK_REQUIRED) {
+        if (simState == IccCard.State.PIN_REQUIRED) {
             currentMode = UnlockMode.SimPin;
+        } else if (simState == IccCard.State.PUK_REQUIRED) {
+            currentMode = UnlockMode.SimPuk;
         } else {
             final int mode = mLockPatternUtils.getKeyguardStoredPasswordQuality();
             switch (mode) {
diff --git a/policy/src/com/android/internal/policy/impl/LockScreen.java b/policy/src/com/android/internal/policy/impl/LockScreen.java
index a9d5ce4..7331bda 100644
--- a/policy/src/com/android/internal/policy/impl/LockScreen.java
+++ b/policy/src/com/android/internal/policy/impl/LockScreen.java
@@ -232,7 +232,7 @@
 
         /** {@inheritDoc} */
         public void onGrabbedStateChange(View v, int grabbedState) {
-            if (DBG) Log.v(TAG, "*** LockScreen accel is " 
+            if (DBG) Log.v(TAG, "*** LockScreen accel is "
                     + (mEnergyWave.isHardwareAccelerated() ? "on":"off"));
             // Don't poke the wake lock when returning to a state where the handle is
             // not grabbed since that can happen when the system (instead of the user)
@@ -579,10 +579,16 @@
                 mScreenLocked.setText(R.string.lockscreen_sim_puk_locked_instructions);
 
                 // layout
-                mScreenLocked.setVisibility(View.VISIBLE);
-                mEmergencyCallText.setVisibility(View.VISIBLE);
-                mEmergencyCallButton.setVisibility(View.VISIBLE);
-                disableUnlock();
+                if (mLockPatternUtils.isPukUnlockScreenEnable()) {
+                    mScreenLocked.setVisibility(View.INVISIBLE);
+                    mEmergencyCallText.setVisibility(View.GONE);
+                    enableUnlock();
+                } else {
+                    mScreenLocked.setVisibility(View.VISIBLE);
+                    mEmergencyCallText.setVisibility(View.VISIBLE);
+                    mEmergencyCallButton.setVisibility(View.VISIBLE);
+                    disableUnlock();
+                }
                 break;
         }
     }
diff --git a/policy/src/com/android/internal/policy/impl/SimPukUnlockScreen.java b/policy/src/com/android/internal/policy/impl/SimPukUnlockScreen.java
new file mode 100644
index 0000000..544bb3d
--- /dev/null
+++ b/policy/src/com/android/internal/policy/impl/SimPukUnlockScreen.java
@@ -0,0 +1,470 @@
+/*
+ * 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.internal.policy.impl;
+
+import android.app.Dialog;
+import android.app.ProgressDialog;
+import android.content.Context;
+import android.content.res.Configuration;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+
+import com.android.internal.telephony.ITelephony;
+import com.android.internal.telephony.IccCard;
+import com.android.internal.widget.LockPatternUtils;
+
+import android.text.Editable;
+import android.util.Log;
+import android.view.KeyEvent;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.WindowManager;
+import android.widget.Button;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+import com.android.internal.R;
+
+/**
+ * Displays a dialer like interface to unlock the SIM PUK.
+ */
+public class SimPukUnlockScreen extends LinearLayout implements KeyguardScreen,
+    View.OnClickListener, KeyguardUpdateMonitor.InfoCallback {
+
+    private static final int DIGIT_PRESS_WAKE_MILLIS = 5000;
+
+    private final KeyguardUpdateMonitor mUpdateMonitor;
+    private final KeyguardScreenCallback mCallback;
+
+    private TextView mHeaderText;
+    private TextView mPukText;
+    private TextView mPinText;
+
+    private TextView mFocusedEntry;
+
+    private TextView mOkButton;
+    private Button mEmergencyCallButton;
+
+    private View mDelPukButton;
+    private View mDelPinButton;
+
+    private ProgressDialog mSimUnlockProgressDialog = null;
+
+    private LockPatternUtils mLockPatternUtils;
+
+    private int mCreationOrientation;
+
+    private int mKeyboardHidden;
+
+    private static final char[] DIGITS = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'};
+
+    public SimPukUnlockScreen(Context context, Configuration configuration,
+            KeyguardUpdateMonitor updateMonitor, KeyguardScreenCallback callback,
+            LockPatternUtils lockpatternutils) {
+        super(context);
+        mUpdateMonitor = updateMonitor;
+        mCallback = callback;;
+
+        mCreationOrientation = configuration.orientation;
+        mKeyboardHidden = configuration.hardKeyboardHidden;
+        mLockPatternUtils = lockpatternutils;
+
+        LayoutInflater inflater = LayoutInflater.from(context);
+        if (mKeyboardHidden == Configuration.HARDKEYBOARDHIDDEN_NO) {
+            inflater.inflate(
+                    R.layout.keyguard_screen_sim_puk_landscape, this, true);
+        } else {
+            inflater.inflate(
+                    R.layout.keyguard_screen_sim_puk_portrait, this, true);
+            new TouchInput();
+        }
+
+        mHeaderText = (TextView) findViewById(R.id.headerText);
+        mPukText = (TextView) findViewById(R.id.pukDisplay);
+        mPukText.setOnClickListener(new OnClickListener() {
+           public void onClick(View v) {
+               requestFocus(mPukText);
+               mCallback.pokeWakelock();
+           }
+        });
+        mPinText = (TextView) findViewById(R.id.pinDisplay);
+        mPinText.setOnClickListener(this);
+
+        mDelPukButton = findViewById(R.id.pukDel);
+        mDelPukButton.setOnClickListener(this);
+        mDelPinButton = findViewById(R.id.pinDel);
+        mDelPinButton.setOnClickListener(this);
+
+
+        mEmergencyCallButton = (Button) findViewById(R.id.emergencyCall);
+        mOkButton = (TextView) findViewById(R.id.ok);
+
+        mHeaderText.setText(R.string.keyguard_password_enter_puk_code);
+        mPukText.setFocusable(false);
+        mPinText.setFocusable(false);
+        mOkButton.setOnClickListener(this);
+
+        requestFocus(mPukText);
+
+        if (mLockPatternUtils.isEmergencyCallCapable()) {
+            mLockPatternUtils.updateEmergencyCallButtonState(mEmergencyCallButton);
+            mEmergencyCallButton.setOnClickListener(this);
+        } else {
+            mEmergencyCallButton.setVisibility(View.GONE);
+        }
+
+        setFocusableInTouchMode(true);
+    }
+
+    private void requestFocus(TextView entry) {
+        mFocusedEntry = entry;
+        mFocusedEntry.setText("");
+    }
+
+    /** {@inheritDoc} */
+    public boolean needsInput() {
+        return true;
+    }
+
+    /** {@inheritDoc} */
+    public void onPause() {
+
+    }
+
+    /** {@inheritDoc} */
+    public void onResume() {
+        // start fresh
+        mHeaderText.setText(R.string.keyguard_password_enter_puk_code);
+        requestFocus(mPukText);
+        mPinText.setText("");
+
+        if (mLockPatternUtils.isEmergencyCallCapable()) {
+            mLockPatternUtils.updateEmergencyCallButtonState(mEmergencyCallButton);
+        }
+    }
+
+    /** {@inheritDoc} */
+    public void cleanUp() {
+        // dismiss the dialog.
+        if (mSimUnlockProgressDialog != null) {
+            mSimUnlockProgressDialog.dismiss();
+            mSimUnlockProgressDialog = null;
+        }
+        mUpdateMonitor.removeCallback(this);
+    }
+
+
+    /**
+     * Since the IPC can block, we want to run the request in a separate thread
+     * with a callback.
+     */
+    private abstract class CheckSimPuk extends Thread {
+
+        private final String mPin, mPuk;
+
+        protected CheckSimPuk(String puk, String pin) {
+            mPuk = puk;
+            mPin = pin;
+        }
+
+        abstract void onSimLockChangedResponse(boolean success);
+
+        @Override
+        public void run() {
+            try {
+                final boolean result = ITelephony.Stub.asInterface(ServiceManager
+                        .checkService("phone")).supplyPuk(mPuk, mPin);
+
+                post(new Runnable() {
+                    public void run() {
+                        onSimLockChangedResponse(result);
+                    }
+                });
+            } catch (RemoteException e) {
+                post(new Runnable() {
+                    public void run() {
+                        onSimLockChangedResponse(false);
+                    }
+                });
+            }
+        }
+    }
+
+    public void onClick(View v) {
+        if (v == mDelPukButton) {
+            final Editable digits = mPukText.getEditableText();
+            final int len = digits.length();
+            if (len > 0) {
+                digits.delete(len-1, len);
+            }
+            mCallback.pokeWakelock();
+        } else if (v == mDelPinButton) {
+            final Editable digits = mPinText.getEditableText();
+            final int len = digits.length();
+            if (len > 0) {
+                digits.delete(len-1, len);
+            }
+            mCallback.pokeWakelock();
+        } else if (v == mPinText) {
+            requestFocus(mPinText);
+            mCallback.pokeWakelock();
+        } else if (v == mEmergencyCallButton) {
+            mCallback.takeEmergencyCallAction();
+        } else if (v == mOkButton) {
+            checkPuk();
+        }
+    }
+
+    private Dialog getSimUnlockProgressDialog() {
+        if (mSimUnlockProgressDialog == null) {
+            mSimUnlockProgressDialog = new ProgressDialog(mContext);
+            mSimUnlockProgressDialog.setMessage(
+                    mContext.getString(R.string.lockscreen_sim_unlock_progress_dialog_message));
+            mSimUnlockProgressDialog.setIndeterminate(true);
+            mSimUnlockProgressDialog.setCancelable(false);
+            mSimUnlockProgressDialog.getWindow().setType(
+                    WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
+            if (!mContext.getResources().getBoolean(
+                    com.android.internal.R.bool.config_sf_slowBlur)) {
+                mSimUnlockProgressDialog.getWindow().setFlags(
+                        WindowManager.LayoutParams.FLAG_BLUR_BEHIND,
+                        WindowManager.LayoutParams.FLAG_BLUR_BEHIND);
+            }
+        }
+        return mSimUnlockProgressDialog;
+    }
+
+    private void checkPuk() {
+        // make sure that the puk is at least 8 digits long.
+        if (mPukText.getText().length() < 8) {
+            // otherwise, display a message to the user, and don't submit.
+            mHeaderText.setText(R.string.invalidPuk);
+            mPukText.setText("");
+            mCallback.pokeWakelock();
+            return;
+        }
+
+        if (mPinText.getText().length() < 4
+                || mPinText.getText().length() > 8) {
+            // otherwise, display a message to the user, and don't submit.
+            mHeaderText.setText(R.string.invalidPin);
+            mPinText.setText("");
+            mCallback.pokeWakelock();
+            return;
+        }
+
+        getSimUnlockProgressDialog().show();
+
+        new CheckSimPuk(mPukText.getText().toString(),
+                mPinText.getText().toString()) {
+            void onSimLockChangedResponse(boolean success) {
+                if (mSimUnlockProgressDialog != null) {
+                    mSimUnlockProgressDialog.hide();
+                }
+                if (success) {
+                    // before closing the keyguard, report back that
+                    // the sim is unlocked so it knows right away
+                    mUpdateMonitor.reportSimUnlocked();
+                    mCallback.goToUnlockScreen();
+                } else {
+                    mHeaderText.setText(R.string.badPuk);
+                    mPukText.setText("");
+                    mPinText.setText("");
+                }
+                mCallback.pokeWakelock();
+            }
+        }.start();
+    }
+
+
+    public boolean onKeyDown(int keyCode, KeyEvent event) {
+        if (keyCode == KeyEvent.KEYCODE_BACK) {
+            mCallback.goToLockScreen();
+            return true;
+        }
+        final char match = event.getMatch(DIGITS);
+        if (match != 0) {
+            reportDigit(match - '0');
+            return true;
+        }
+        if (keyCode == KeyEvent.KEYCODE_DEL) {
+            mFocusedEntry.onKeyDown(keyCode, event);
+            final Editable digits = mFocusedEntry.getEditableText();
+            final int len = digits.length();
+            if (len > 0) {
+                digits.delete(len-1, len);
+            }
+            mCallback.pokeWakelock();
+            return true;
+        }
+
+        if (keyCode == KeyEvent.KEYCODE_ENTER) {
+            checkPuk();
+            return true;
+        }
+
+        return false;
+    }
+
+    private void reportDigit(int digit) {
+        mFocusedEntry.append(Integer.toString(digit));
+    }
+
+    void updateConfiguration() {
+        Configuration newConfig = getResources().getConfiguration();
+        if (newConfig.orientation != mCreationOrientation) {
+            mCallback.recreateMe(newConfig);
+        } else if (newConfig.hardKeyboardHidden != mKeyboardHidden) {
+            mKeyboardHidden = newConfig.hardKeyboardHidden;
+            final boolean isKeyboardOpen =
+                (mKeyboardHidden == Configuration.HARDKEYBOARDHIDDEN_NO);
+            if (mUpdateMonitor.isKeyguardBypassEnabled() && isKeyboardOpen) {
+                mCallback.goToUnlockScreen();
+            }
+        }
+
+    }
+
+    @Override
+    protected void onAttachedToWindow() {
+        super.onAttachedToWindow();
+        updateConfiguration();
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    protected void onConfigurationChanged(Configuration newConfig) {
+        super.onConfigurationChanged(newConfig);
+        updateConfiguration();
+    }
+
+    /**
+     * Helper class to handle input from touch dialer.  Only relevant when
+     * the keyboard is shut.
+     */
+    private class TouchInput implements View.OnClickListener {
+        private TextView mZero;
+        private TextView mOne;
+        private TextView mTwo;
+        private TextView mThree;
+        private TextView mFour;
+        private TextView mFive;
+        private TextView mSix;
+        private TextView mSeven;
+        private TextView mEight;
+        private TextView mNine;
+        private TextView mCancelButton;
+
+        private TouchInput() {
+            mZero = (TextView) findViewById(R.id.zero);
+            mOne = (TextView) findViewById(R.id.one);
+            mTwo = (TextView) findViewById(R.id.two);
+            mThree = (TextView) findViewById(R.id.three);
+            mFour = (TextView) findViewById(R.id.four);
+            mFive = (TextView) findViewById(R.id.five);
+            mSix = (TextView) findViewById(R.id.six);
+            mSeven = (TextView) findViewById(R.id.seven);
+            mEight = (TextView) findViewById(R.id.eight);
+            mNine = (TextView) findViewById(R.id.nine);
+            mCancelButton = (TextView) findViewById(R.id.cancel);
+
+            mZero.setText("0");
+            mOne.setText("1");
+            mTwo.setText("2");
+            mThree.setText("3");
+            mFour.setText("4");
+            mFive.setText("5");
+            mSix.setText("6");
+            mSeven.setText("7");
+            mEight.setText("8");
+            mNine.setText("9");
+
+            mZero.setOnClickListener(this);
+            mOne.setOnClickListener(this);
+            mTwo.setOnClickListener(this);
+            mThree.setOnClickListener(this);
+            mFour.setOnClickListener(this);
+            mFive.setOnClickListener(this);
+            mSix.setOnClickListener(this);
+            mSeven.setOnClickListener(this);
+            mEight.setOnClickListener(this);
+            mNine.setOnClickListener(this);
+            mCancelButton.setOnClickListener(this);
+        }
+
+
+        public void onClick(View v) {
+            if (v == mCancelButton) {
+                mCallback.goToLockScreen();
+                return;
+            }
+
+            final int digit = checkDigit(v);
+            if (digit >= 0) {
+                mCallback.pokeWakelock(DIGIT_PRESS_WAKE_MILLIS);
+                reportDigit(digit);
+            }
+        }
+
+        private int checkDigit(View v) {
+            int digit = -1;
+            if (v == mZero) {
+                digit = 0;
+            } else if (v == mOne) {
+                digit = 1;
+            } else if (v == mTwo) {
+                digit = 2;
+            } else if (v == mThree) {
+                digit = 3;
+            } else if (v == mFour) {
+                digit = 4;
+            } else if (v == mFive) {
+                digit = 5;
+            } else if (v == mSix) {
+                digit = 6;
+            } else if (v == mSeven) {
+                digit = 7;
+            } else if (v == mEight) {
+                digit = 8;
+            } else if (v == mNine) {
+                digit = 9;
+            }
+            return digit;
+        }
+    }
+
+    public void onPhoneStateChanged(String newState) {
+        if (mLockPatternUtils.isEmergencyCallCapable()) {
+            mLockPatternUtils.updateEmergencyCallButtonState(mEmergencyCallButton);
+        }
+    }
+
+    public void onRefreshBatteryInfo(boolean showBatteryInfo, boolean pluggedIn, int batteryLevel) {
+
+    }
+
+    public void onRefreshCarrierInfo(CharSequence plmn, CharSequence spn) {
+
+    }
+
+    public void onRingerModeChanged(int state) {
+
+    }
+
+    public void onTimeChanged() {
+
+    }
+}
diff --git a/policy/src/com/android/internal/policy/impl/SimUnlockScreen.java b/policy/src/com/android/internal/policy/impl/SimUnlockScreen.java
index 486e7aa..7255c27 100644
--- a/policy/src/com/android/internal/policy/impl/SimUnlockScreen.java
+++ b/policy/src/com/android/internal/policy/impl/SimUnlockScreen.java
@@ -92,16 +92,17 @@
         mBackSpaceButton = findViewById(R.id.backspace);
         mBackSpaceButton.setOnClickListener(this);
 
-        mEmergencyCallButton = (Button) findViewById(R.id.emergencyCall);
-        mLockPatternUtils.updateEmergencyCallButtonState(mEmergencyCallButton);
         mOkButton = (TextView) findViewById(R.id.ok);
 
         mHeaderText.setText(R.string.keyguard_password_enter_pin_code);
         mPinText.setFocusable(false);
 
-        mEmergencyCallButton.setOnClickListener(this);
         mOkButton.setOnClickListener(this);
 
+        mEmergencyCallButton = (Button) findViewById(R.id.emergencyCall);
+        mEmergencyCallButton.setOnClickListener(this);
+        mLockPatternUtils.updateEmergencyCallButtonState(mEmergencyCallButton);
+
         setFocusableInTouchMode(true);
     }
 
@@ -229,7 +230,7 @@
                 if (success) {
                     // before closing the keyguard, report back that
                     // the sim is unlocked so it knows right away
-                    mUpdateMonitor.reportSimPinUnlocked();
+                    mUpdateMonitor.reportSimUnlocked();
                     mCallback.goToUnlockScreen();
                 } else {
                     mHeaderText.setText(R.string.keyguard_password_wrong_pin_code);
@@ -291,9 +292,8 @@
                 mCallback.goToUnlockScreen();
             }
         }
-        
     }
-    
+
     @Override
     protected void onAttachedToWindow() {
         super.onAttachedToWindow();
@@ -403,7 +403,7 @@
     }
 
     public void onPhoneStateChanged(String newState) {
-        mLockPatternUtils.updateEmergencyCallButtonState(mEmergencyCallButton);
+            mLockPatternUtils.updateEmergencyCallButtonState(mEmergencyCallButton);
     }
 
     public void onRefreshBatteryInfo(boolean showBatteryInfo, boolean pluggedIn, int batteryLevel) {
diff --git a/services/input/InputReader.cpp b/services/input/InputReader.cpp
index a22ec1c..ce8a9397 100644
--- a/services/input/InputReader.cpp
+++ b/services/input/InputReader.cpp
@@ -186,23 +186,6 @@
     return edgeFlags;
 }
 
-static void clampPositionUsingPointerBounds(
-        const sp<PointerControllerInterface>& pointerController, float* x, float* y) {
-    float minX, minY, maxX, maxY;
-    if (pointerController->getBounds(&minX, &minY, &maxX, &maxY)) {
-        if (*x < minX) {
-            *x = minX;
-        } else if (*x > maxX) {
-            *x = maxX;
-        }
-        if (*y < minY) {
-            *y = minY;
-        } else if (*y > maxY) {
-            *y = maxY;
-        }
-    }
-}
-
 static float calculateCommonVector(float a, float b) {
     if (a > 0 && b > 0) {
         return a < b ? a : b;
@@ -746,8 +729,8 @@
             mConfig.pointerGestureTapSlop);
     dump.appendFormat(INDENT3 "MultitouchSettleInterval: %0.1fms\n",
             mConfig.pointerGestureMultitouchSettleInterval * 0.000001f);
-    dump.appendFormat(INDENT3 "MultitouchMinSpeed: %0.1fpx/s\n",
-            mConfig.pointerGestureMultitouchMinSpeed);
+    dump.appendFormat(INDENT3 "MultitouchMinDistance: %0.1fpx\n",
+            mConfig.pointerGestureMultitouchMinDistance);
     dump.appendFormat(INDENT3 "SwipeTransitionAngleCosine: %0.1f\n",
             mConfig.pointerGestureSwipeTransitionAngleCosine);
     dump.appendFormat(INDENT3 "SwipeMaxWidthRatio: %0.1f\n",
@@ -3291,11 +3274,18 @@
         cancelPreviousGesture = false;
     }
 
-    // Switch pointer presentation.
-    mPointerController->setPresentation(
-            mParameters.gestureMode == Parameters::GESTURE_MODE_SPOTS
-                    ? PointerControllerInterface::PRESENTATION_SPOT
-                    : PointerControllerInterface::PRESENTATION_POINTER);
+    // Update the pointer presentation and spots.
+    if (mParameters.gestureMode == Parameters::GESTURE_MODE_SPOTS) {
+        mPointerController->setPresentation(PointerControllerInterface::PRESENTATION_SPOT);
+        if (finishPreviousGesture || cancelPreviousGesture) {
+            mPointerController->clearSpots();
+        }
+        mPointerController->setSpots(mPointerGesture.currentGestureCoords,
+                mPointerGesture.currentGestureIdToIndex,
+                mPointerGesture.currentGestureIdBits);
+    } else {
+        mPointerController->setPresentation(PointerControllerInterface::PRESENTATION_POINTER);
+    }
 
     // Show or hide the pointer if needed.
     switch (mPointerGesture.currentGestureMode) {
@@ -3480,12 +3470,6 @@
                 mPointerGesture.currentGestureIdBits.clear();
 
                 mPointerGesture.pointerVelocityControl.reset();
-
-                if (mParameters.gestureMode == Parameters::GESTURE_MODE_SPOTS) {
-                    mPointerGesture.spotGesture = PointerControllerInterface::SPOT_GESTURE_NEUTRAL;
-                    mPointerGesture.spotIdBits.clear();
-                    moveSpotsLocked();
-                }
                 return true;
             }
         }
@@ -3566,22 +3550,18 @@
     if (isQuietTime) {
         // Case 1: Quiet time. (QUIET)
 #if DEBUG_GESTURES
-        LOGD("Gestures: QUIET for next %0.3fms",
-                (mPointerGesture.quietTime + QUIET_INTERVAL - when) * 0.000001f);
+        LOGD("Gestures: QUIET for next %0.3fms", (mPointerGesture.quietTime
+                + mConfig->pointerGestureQuietInterval - when) * 0.000001f);
 #endif
-        *outFinishPreviousGesture = true;
+        if (mPointerGesture.lastGestureMode != PointerGesture::QUIET) {
+            *outFinishPreviousGesture = true;
+        }
 
         mPointerGesture.activeGestureId = -1;
         mPointerGesture.currentGestureMode = PointerGesture::QUIET;
         mPointerGesture.currentGestureIdBits.clear();
 
         mPointerGesture.pointerVelocityControl.reset();
-
-        if (mParameters.gestureMode == Parameters::GESTURE_MODE_SPOTS) {
-            mPointerGesture.spotGesture = PointerControllerInterface::SPOT_GESTURE_NEUTRAL;
-            mPointerGesture.spotIdBits.clear();
-            moveSpotsLocked();
-        }
     } else if (isPointerDown(mCurrentTouch.buttonState)) {
         // Case 2: Button is pressed. (BUTTON_CLICK_OR_DRAG)
         // The pointer follows the active touch point.
@@ -3663,32 +3643,11 @@
         mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X, x);
         mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_Y, y);
         mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, 1.0f);
-
-        if (mParameters.gestureMode == Parameters::GESTURE_MODE_SPOTS) {
-            if (activeTouchId >= 0) {
-                // Collapse all spots into one point at the pointer location.
-                mPointerGesture.spotGesture = PointerControllerInterface::SPOT_GESTURE_BUTTON_DRAG;
-                mPointerGesture.spotIdBits.clear();
-                for (uint32_t i = 0; i < mCurrentTouch.pointerCount; i++) {
-                    uint32_t id = mCurrentTouch.pointers[i].id;
-                    mPointerGesture.spotIdBits.markBit(id);
-                    mPointerGesture.spotIdToIndex[id] = i;
-                    mPointerGesture.spotCoords[i] = mPointerGesture.currentGestureCoords[0];
-                }
-            } else {
-                // No fingers.  Generate a spot at the pointer location so the
-                // anchor appears to be pressed.
-                mPointerGesture.spotGesture = PointerControllerInterface::SPOT_GESTURE_BUTTON_CLICK;
-                mPointerGesture.spotIdBits.clear();
-                mPointerGesture.spotIdBits.markBit(0);
-                mPointerGesture.spotIdToIndex[0] = 0;
-                mPointerGesture.spotCoords[0] = mPointerGesture.currentGestureCoords[0];
-            }
-            moveSpotsLocked();
-        }
     } else if (mCurrentTouch.pointerCount == 0) {
         // Case 3. No fingers down and button is not pressed. (NEUTRAL)
-        *outFinishPreviousGesture = true;
+        if (mPointerGesture.lastGestureMode != PointerGesture::NEUTRAL) {
+            *outFinishPreviousGesture = true;
+        }
 
         // Watch for taps coming out of HOVER or TAP_DRAG mode.
         // Checking for taps after TAP_DRAG allows us to detect double-taps.
@@ -3724,15 +3683,6 @@
                     mPointerGesture.currentGestureCoords[0].setAxisValue(
                             AMOTION_EVENT_AXIS_PRESSURE, 1.0f);
 
-                    if (mParameters.gestureMode == Parameters::GESTURE_MODE_SPOTS) {
-                        mPointerGesture.spotGesture = PointerControllerInterface::SPOT_GESTURE_TAP;
-                        mPointerGesture.spotIdBits.clear();
-                        mPointerGesture.spotIdBits.markBit(lastActiveTouchId);
-                        mPointerGesture.spotIdToIndex[lastActiveTouchId] = 0;
-                        mPointerGesture.spotCoords[0] = mPointerGesture.currentGestureCoords[0];
-                        moveSpotsLocked();
-                    }
-
                     tapped = true;
                 } else {
 #if DEBUG_GESTURES
@@ -3758,12 +3708,6 @@
             mPointerGesture.activeGestureId = -1;
             mPointerGesture.currentGestureMode = PointerGesture::NEUTRAL;
             mPointerGesture.currentGestureIdBits.clear();
-
-            if (mParameters.gestureMode == Parameters::GESTURE_MODE_SPOTS) {
-                mPointerGesture.spotGesture = PointerControllerInterface::SPOT_GESTURE_NEUTRAL;
-                mPointerGesture.spotIdBits.clear();
-                moveSpotsLocked();
-            }
         }
     } else if (mCurrentTouch.pointerCount == 1) {
         // Case 4. Exactly one finger down, button is not pressed. (HOVER or TAP_DRAG)
@@ -3826,7 +3770,9 @@
 #if DEBUG_GESTURES
             LOGD("Gestures: HOVER");
 #endif
-            *outFinishPreviousGesture = true;
+            if (mPointerGesture.lastGestureMode != PointerGesture::HOVER) {
+                *outFinishPreviousGesture = true;
+            }
             mPointerGesture.activeGestureId = 0;
             down = false;
         }
@@ -3849,16 +3795,6 @@
             mPointerGesture.tapX = x;
             mPointerGesture.tapY = y;
         }
-
-        if (mParameters.gestureMode == Parameters::GESTURE_MODE_SPOTS) {
-            mPointerGesture.spotGesture = down ? PointerControllerInterface::SPOT_GESTURE_DRAG
-                    : PointerControllerInterface::SPOT_GESTURE_HOVER;
-            mPointerGesture.spotIdBits.clear();
-            mPointerGesture.spotIdBits.markBit(activeTouchId);
-            mPointerGesture.spotIdToIndex[activeTouchId] = 0;
-            mPointerGesture.spotCoords[0] = mPointerGesture.currentGestureCoords[0];
-            moveSpotsLocked();
-        }
     } else {
         // Case 5. At least two fingers down, button is not pressed. (PRESS, SWIPE or FREEFORM)
         // We need to provide feedback for each finger that goes down so we cannot wait
@@ -3886,8 +3822,8 @@
             // Reset the gesture.
 #if DEBUG_GESTURES
             LOGD("Gestures: Resetting gesture since additional pointers went down for MULTITOUCH, "
-                    "settle time remaining %0.3fms",
-                    (mPointerGesture.firstTouchTime + MULTITOUCH_SETTLE_INTERVAL - when)
+                    "settle time remaining %0.3fms", (mPointerGesture.firstTouchTime
+                            + mConfig->pointerGestureMultitouchSettleInterval - when)
                             * 0.000001f);
 #endif
             *outCancelPreviousGesture = true;
@@ -3902,101 +3838,134 @@
             mPointerGesture.referenceIdBits.clear();
             mPointerGesture.pointerVelocityControl.reset();
 
-            if (settled && mParameters.gestureMode == Parameters::GESTURE_MODE_SPOTS
-                    && mLastTouch.idBits.hasBit(mPointerGesture.activeTouchId)) {
-                // The spot is already visible and has settled, use it as the reference point
-                // for the gesture.  Other spots will be positioned relative to this one.
+            // Use the centroid and pointer location as the reference points for the gesture.
 #if DEBUG_GESTURES
-                LOGD("Gestures: Using active spot as reference for MULTITOUCH, "
-                        "settle time expired %0.3fms ago",
-                        (when - mPointerGesture.firstTouchTime - MULTITOUCH_SETTLE_INTERVAL)
-                                * 0.000001f);
+            LOGD("Gestures: Using centroid as reference for MULTITOUCH, "
+                    "settle time remaining %0.3fms", (mPointerGesture.firstTouchTime
+                            + mConfig->pointerGestureMultitouchSettleInterval - when)
+                            * 0.000001f);
 #endif
-                const PointerData& d = mLastTouch.pointers[mLastTouch.idToIndex[
-                        mPointerGesture.activeTouchId]];
-                mPointerGesture.referenceTouchX = d.x;
-                mPointerGesture.referenceTouchY = d.y;
-                const PointerCoords& c = mPointerGesture.spotCoords[mPointerGesture.spotIdToIndex[
-                        mPointerGesture.activeTouchId]];
-                mPointerGesture.referenceGestureX = c.getAxisValue(AMOTION_EVENT_AXIS_X);
-                mPointerGesture.referenceGestureY = c.getAxisValue(AMOTION_EVENT_AXIS_Y);
+            mCurrentTouch.getCentroid(&mPointerGesture.referenceTouchX,
+                    &mPointerGesture.referenceTouchY);
+            mPointerController->getPosition(&mPointerGesture.referenceGestureX,
+                    &mPointerGesture.referenceGestureY);
+        }
+
+        // Clear the reference deltas for fingers not yet included in the reference calculation.
+        for (BitSet32 idBits(mCurrentTouch.idBits.value & ~mPointerGesture.referenceIdBits.value);
+                !idBits.isEmpty(); ) {
+            uint32_t id = idBits.firstMarkedBit();
+            idBits.clearBit(id);
+
+            mPointerGesture.referenceDeltas[id].dx = 0;
+            mPointerGesture.referenceDeltas[id].dy = 0;
+        }
+        mPointerGesture.referenceIdBits = mCurrentTouch.idBits;
+
+        // Add delta for all fingers and calculate a common movement delta.
+        float commonDeltaX = 0, commonDeltaY = 0;
+        BitSet32 commonIdBits(mLastTouch.idBits.value & mCurrentTouch.idBits.value);
+        for (BitSet32 idBits(commonIdBits); !idBits.isEmpty(); ) {
+            bool first = (idBits == commonIdBits);
+            uint32_t id = idBits.firstMarkedBit();
+            idBits.clearBit(id);
+
+            const PointerData& cpd = mCurrentTouch.pointers[mCurrentTouch.idToIndex[id]];
+            const PointerData& lpd = mLastTouch.pointers[mLastTouch.idToIndex[id]];
+            PointerGesture::Delta& delta = mPointerGesture.referenceDeltas[id];
+            delta.dx += cpd.x - lpd.x;
+            delta.dy += cpd.y - lpd.y;
+
+            if (first) {
+                commonDeltaX = delta.dx;
+                commonDeltaY = delta.dy;
             } else {
-                // Use the centroid and pointer location as the reference points for the gesture.
-#if DEBUG_GESTURES
-                LOGD("Gestures: Using centroid as reference for MULTITOUCH, "
-                        "settle time remaining %0.3fms",
-                        (mPointerGesture.firstTouchTime + MULTITOUCH_SETTLE_INTERVAL - when)
-                                * 0.000001f);
-#endif
-                mCurrentTouch.getCentroid(&mPointerGesture.referenceTouchX,
-                        &mPointerGesture.referenceTouchY);
-                mPointerController->getPosition(&mPointerGesture.referenceGestureX,
-                        &mPointerGesture.referenceGestureY);
+                commonDeltaX = calculateCommonVector(commonDeltaX, delta.dx);
+                commonDeltaY = calculateCommonVector(commonDeltaY, delta.dy);
             }
         }
 
+        // Consider transitions from PRESS to SWIPE or MULTITOUCH.
         if (mPointerGesture.currentGestureMode == PointerGesture::PRESS) {
-            float d;
-            if (mCurrentTouch.pointerCount > 2) {
-                // There are more than two pointers, switch to FREEFORM.
-#if DEBUG_GESTURES
-                LOGD("Gestures: PRESS transitioned to FREEFORM, number of pointers %d > 2",
-                        mCurrentTouch.pointerCount);
-#endif
-                *outCancelPreviousGesture = true;
-                mPointerGesture.currentGestureMode = PointerGesture::FREEFORM;
-            } else if (((d = distance(
-                    mCurrentTouch.pointers[0].x, mCurrentTouch.pointers[0].y,
-                    mCurrentTouch.pointers[1].x, mCurrentTouch.pointers[1].y))
-                            > mLocked.pointerGestureMaxSwipeWidth)) {
-                // There are two pointers but they are too far apart, switch to FREEFORM.
-#if DEBUG_GESTURES
-                LOGD("Gestures: PRESS transitioned to FREEFORM, distance %0.3f > %0.3f",
-                        d, mLocked.pointerGestureMaxSwipeWidth);
-#endif
-                *outCancelPreviousGesture = true;
-                mPointerGesture.currentGestureMode = PointerGesture::FREEFORM;
-            } else {
-                // There are two pointers.  Wait for both pointers to start moving
-                // before deciding whether this is a SWIPE or FREEFORM gesture.
-                uint32_t id1 = mCurrentTouch.pointers[0].id;
-                uint32_t id2 = mCurrentTouch.pointers[1].id;
+            float dist[MAX_POINTER_ID + 1];
+            int32_t distOverThreshold = 0;
+            for (BitSet32 idBits(mPointerGesture.referenceIdBits); !idBits.isEmpty(); ) {
+                uint32_t id = idBits.firstMarkedBit();
+                idBits.clearBit(id);
 
-                float vx1, vy1, vx2, vy2;
-                mPointerGesture.velocityTracker.getVelocity(id1, &vx1, &vy1);
-                mPointerGesture.velocityTracker.getVelocity(id2, &vx2, &vy2);
+                PointerGesture::Delta& delta = mPointerGesture.referenceDeltas[id];
+                dist[id] = hypotf(delta.dx * mLocked.pointerGestureXZoomScale,
+                        delta.dy * mLocked.pointerGestureYZoomScale);
+                if (dist[id] > mConfig->pointerGestureMultitouchMinDistance) {
+                    distOverThreshold += 1;
+                }
+            }
 
-                float speed1 = hypotf(vx1, vy1);
-                float speed2 = hypotf(vx2, vy2);
-                if (speed1 >= mConfig->pointerGestureMultitouchMinSpeed
-                        && speed2 >= mConfig->pointerGestureMultitouchMinSpeed) {
-                    // Calculate the dot product of the velocity vectors.
-                    // When the vectors are oriented in approximately the same direction,
-                    // the angle betweeen them is near zero and the cosine of the angle
-                    // approches 1.0.  Recall that dot(v1, v2) = cos(angle) * mag(v1) * mag(v2).
-                    float dot = vx1 * vx2 + vy1 * vy2;
-                    float cosine = dot / (speed1 * speed2); // denominator always > 0
-                    if (cosine >= mConfig->pointerGestureSwipeTransitionAngleCosine) {
-                        // Pointers are moving in the same direction.  Switch to SWIPE.
+            // Only transition when at least two pointers have moved further than
+            // the minimum distance threshold.
+            if (distOverThreshold >= 2) {
+                float d;
+                if (mCurrentTouch.pointerCount > 2) {
+                    // There are more than two pointers, switch to FREEFORM.
 #if DEBUG_GESTURES
-                        LOGD("Gestures: PRESS transitioned to SWIPE, "
-                                "speed1 %0.3f >= %0.3f, speed2 %0.3f >= %0.3f, "
-                                "cosine %0.3f >= %0.3f",
-                                speed1, MULTITOUCH_MIN_SPEED, speed2, MULTITOUCH_MIN_SPEED,
-                                cosine, SWIPE_TRANSITION_ANGLE_COSINE);
+                    LOGD("Gestures: PRESS transitioned to FREEFORM, number of pointers %d > 2",
+                            mCurrentTouch.pointerCount);
 #endif
-                        mPointerGesture.currentGestureMode = PointerGesture::SWIPE;
-                    } else {
-                        // Pointers are moving in different directions.  Switch to FREEFORM.
+                    *outCancelPreviousGesture = true;
+                    mPointerGesture.currentGestureMode = PointerGesture::FREEFORM;
+                } else if (((d = distance(
+                        mCurrentTouch.pointers[0].x, mCurrentTouch.pointers[0].y,
+                        mCurrentTouch.pointers[1].x, mCurrentTouch.pointers[1].y))
+                                > mLocked.pointerGestureMaxSwipeWidth)) {
+                    // There are two pointers but they are too far apart for a SWIPE,
+                    // switch to FREEFORM.
 #if DEBUG_GESTURES
-                        LOGD("Gestures: PRESS transitioned to FREEFORM, "
-                                "speed1 %0.3f >= %0.3f, speed2 %0.3f >= %0.3f, "
-                                "cosine %0.3f < %0.3f",
-                                speed1, MULTITOUCH_MIN_SPEED, speed2, MULTITOUCH_MIN_SPEED,
-                                cosine, SWIPE_TRANSITION_ANGLE_COSINE);
+                    LOGD("Gestures: PRESS transitioned to FREEFORM, distance %0.3f > %0.3f",
+                            d, mLocked.pointerGestureMaxSwipeWidth);
 #endif
-                        *outCancelPreviousGesture = true;
-                        mPointerGesture.currentGestureMode = PointerGesture::FREEFORM;
+                    *outCancelPreviousGesture = true;
+                    mPointerGesture.currentGestureMode = PointerGesture::FREEFORM;
+                } else {
+                    // There are two pointers.  Wait for both pointers to start moving
+                    // before deciding whether this is a SWIPE or FREEFORM gesture.
+                    uint32_t id1 = mCurrentTouch.pointers[0].id;
+                    uint32_t id2 = mCurrentTouch.pointers[1].id;
+                    float dist1 = dist[id1];
+                    float dist2 = dist[id2];
+                    if (dist1 >= mConfig->pointerGestureMultitouchMinDistance
+                            && dist2 >= mConfig->pointerGestureMultitouchMinDistance) {
+                        // Calculate the dot product of the displacement vectors.
+                        // When the vectors are oriented in approximately the same direction,
+                        // the angle betweeen them is near zero and the cosine of the angle
+                        // approches 1.0.  Recall that dot(v1, v2) = cos(angle) * mag(v1) * mag(v2).
+                        PointerGesture::Delta& delta1 = mPointerGesture.referenceDeltas[id1];
+                        PointerGesture::Delta& delta2 = mPointerGesture.referenceDeltas[id2];
+                        float dot = delta1.dx * delta2.dx + delta1.dy * delta2.dy;
+                        float cosine = dot / (dist1 * dist2); // denominator always > 0
+                        if (cosine >= mConfig->pointerGestureSwipeTransitionAngleCosine) {
+                            // Pointers are moving in the same direction.  Switch to SWIPE.
+#if DEBUG_GESTURES
+                            LOGD("Gestures: PRESS transitioned to SWIPE, "
+                                    "dist1 %0.3f >= %0.3f, dist2 %0.3f >= %0.3f, "
+                                    "cosine %0.3f >= %0.3f",
+                                    dist1, mConfig->pointerGestureMultitouchMinDistance,
+                                    dist2, mConfig->pointerGestureMultitouchMinDistance,
+                                    cosine, mConfig->pointerGestureSwipeTransitionAngleCosine);
+#endif
+                            mPointerGesture.currentGestureMode = PointerGesture::SWIPE;
+                        } else {
+                            // Pointers are moving in different directions.  Switch to FREEFORM.
+#if DEBUG_GESTURES
+                            LOGD("Gestures: PRESS transitioned to FREEFORM, "
+                                    "dist1 %0.3f >= %0.3f, dist2 %0.3f >= %0.3f, "
+                                    "cosine %0.3f < %0.3f",
+                                    dist1, mConfig->pointerGestureMultitouchMinDistance,
+                                    dist2, mConfig->pointerGestureMultitouchMinDistance,
+                                    cosine, mConfig->pointerGestureSwipeTransitionAngleCosine);
+#endif
+                            *outCancelPreviousGesture = true;
+                            mPointerGesture.currentGestureMode = PointerGesture::FREEFORM;
+                        }
                     }
                 }
             }
@@ -4013,67 +3982,28 @@
             }
         }
 
-        // Clear the reference deltas for fingers not yet included in the reference calculation.
-        for (BitSet32 idBits(mCurrentTouch.idBits.value & ~mPointerGesture.referenceIdBits.value);
-                !idBits.isEmpty(); ) {
-            uint32_t id = idBits.firstMarkedBit();
-            idBits.clearBit(id);
-
-            mPointerGesture.referenceDeltas[id].dx = 0;
-            mPointerGesture.referenceDeltas[id].dy = 0;
-        }
-        mPointerGesture.referenceIdBits = mCurrentTouch.idBits;
-
-        // Move the reference points based on the overall group motion of the fingers.
-        // The objective is to calculate a vector delta that is common to the movement
-        // of all fingers.
-        BitSet32 commonIdBits(mLastTouch.idBits.value & mCurrentTouch.idBits.value);
-        if (!commonIdBits.isEmpty()) {
-            float commonDeltaX = 0, commonDeltaY = 0;
-            for (BitSet32 idBits(commonIdBits); !idBits.isEmpty(); ) {
-                bool first = (idBits == commonIdBits);
+        // Move the reference points based on the overall group motion of the fingers
+        // except in PRESS mode while waiting for a transition to occur.
+        if (mPointerGesture.currentGestureMode != PointerGesture::PRESS
+                && (commonDeltaX || commonDeltaY)) {
+            for (BitSet32 idBits(mPointerGesture.referenceIdBits); !idBits.isEmpty(); ) {
                 uint32_t id = idBits.firstMarkedBit();
                 idBits.clearBit(id);
 
-                const PointerData& cpd = mCurrentTouch.pointers[mCurrentTouch.idToIndex[id]];
-                const PointerData& lpd = mLastTouch.pointers[mLastTouch.idToIndex[id]];
                 PointerGesture::Delta& delta = mPointerGesture.referenceDeltas[id];
-                delta.dx += cpd.x - lpd.x;
-                delta.dy += cpd.y - lpd.y;
-
-                if (first) {
-                    commonDeltaX = delta.dx;
-                    commonDeltaY = delta.dy;
-                } else {
-                    commonDeltaX = calculateCommonVector(commonDeltaX, delta.dx);
-                    commonDeltaY = calculateCommonVector(commonDeltaY, delta.dy);
-                }
+                delta.dx = 0;
+                delta.dy = 0;
             }
 
-            if (commonDeltaX || commonDeltaY) {
-                for (BitSet32 idBits(commonIdBits); !idBits.isEmpty(); ) {
-                    uint32_t id = idBits.firstMarkedBit();
-                    idBits.clearBit(id);
+            mPointerGesture.referenceTouchX += commonDeltaX;
+            mPointerGesture.referenceTouchY += commonDeltaY;
 
-                    PointerGesture::Delta& delta = mPointerGesture.referenceDeltas[id];
-                    delta.dx = 0;
-                    delta.dy = 0;
-                }
+            commonDeltaX *= mLocked.pointerGestureXMovementScale;
+            commonDeltaY *= mLocked.pointerGestureYMovementScale;
+            mPointerGesture.pointerVelocityControl.move(when, &commonDeltaX, &commonDeltaY);
 
-                mPointerGesture.referenceTouchX += commonDeltaX;
-                mPointerGesture.referenceTouchY += commonDeltaY;
-
-                commonDeltaX *= mLocked.pointerGestureXMovementScale;
-                commonDeltaY *= mLocked.pointerGestureYMovementScale;
-                mPointerGesture.pointerVelocityControl.move(when, &commonDeltaX, &commonDeltaY);
-
-                mPointerGesture.referenceGestureX += commonDeltaX;
-                mPointerGesture.referenceGestureY += commonDeltaY;
-
-                clampPositionUsingPointerBounds(mPointerController,
-                        &mPointerGesture.referenceGestureX,
-                        &mPointerGesture.referenceGestureY);
-            }
+            mPointerGesture.referenceGestureX += commonDeltaX;
+            mPointerGesture.referenceGestureY += commonDeltaY;
         }
 
         // Report gestures.
@@ -4095,10 +4025,6 @@
             mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_Y,
                     mPointerGesture.referenceGestureY);
             mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, 1.0f);
-
-            if (mParameters.gestureMode == Parameters::GESTURE_MODE_SPOTS) {
-                mPointerGesture.spotGesture = PointerControllerInterface::SPOT_GESTURE_PRESS;
-            }
         } else if (mPointerGesture.currentGestureMode == PointerGesture::SWIPE) {
             // SWIPE mode.
 #if DEBUG_GESTURES
@@ -4117,10 +4043,6 @@
             mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_Y,
                     mPointerGesture.referenceGestureY);
             mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, 1.0f);
-
-            if (mParameters.gestureMode == Parameters::GESTURE_MODE_SPOTS) {
-                mPointerGesture.spotGesture = PointerControllerInterface::SPOT_GESTURE_SWIPE;
-            }
         } else if (mPointerGesture.currentGestureMode == PointerGesture::FREEFORM) {
             // FREEFORM mode.
 #if DEBUG_GESTURES
@@ -4218,33 +4140,6 @@
                         "activeGestureId=%d", mPointerGesture.activeGestureId);
 #endif
             }
-
-            if (mParameters.gestureMode == Parameters::GESTURE_MODE_SPOTS) {
-                mPointerGesture.spotGesture = PointerControllerInterface::SPOT_GESTURE_FREEFORM;
-            }
-        }
-
-        // Update spot locations for PRESS, SWIPE and FREEFORM.
-        // We use the same calculation as we do to calculate the gesture pointers
-        // for FREEFORM so that the spots smoothly track gestures.
-        if (mParameters.gestureMode == Parameters::GESTURE_MODE_SPOTS) {
-            mPointerGesture.spotIdBits.clear();
-            for (uint32_t i = 0; i < mCurrentTouch.pointerCount; i++) {
-                uint32_t id = mCurrentTouch.pointers[i].id;
-                mPointerGesture.spotIdBits.markBit(id);
-                mPointerGesture.spotIdToIndex[id] = i;
-
-                float x = (mCurrentTouch.pointers[i].x - mPointerGesture.referenceTouchX)
-                        * mLocked.pointerGestureXZoomScale + mPointerGesture.referenceGestureX;
-                float y = (mCurrentTouch.pointers[i].y - mPointerGesture.referenceTouchY)
-                        * mLocked.pointerGestureYZoomScale + mPointerGesture.referenceGestureY;
-
-                mPointerGesture.spotCoords[i].clear();
-                mPointerGesture.spotCoords[i].setAxisValue(AMOTION_EVENT_AXIS_X, x);
-                mPointerGesture.spotCoords[i].setAxisValue(AMOTION_EVENT_AXIS_Y, y);
-                mPointerGesture.spotCoords[i].setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, 1.0f);
-            }
-            moveSpotsLocked();
         }
     }
 
@@ -4281,11 +4176,6 @@
     return true;
 }
 
-void TouchInputMapper::moveSpotsLocked() {
-    mPointerController->setSpots(mPointerGesture.spotGesture,
-            mPointerGesture.spotCoords, mPointerGesture.spotIdToIndex, mPointerGesture.spotIdBits);
-}
-
 void TouchInputMapper::dispatchMotion(nsecs_t when, uint32_t policyFlags, uint32_t source,
         int32_t action, int32_t flags, uint32_t metaState, int32_t edgeFlags,
         const PointerCoords* coords, const uint32_t* idToIndex, BitSet32 idBits,
diff --git a/services/input/InputReader.h b/services/input/InputReader.h
index 5028b60..82faf7d 100644
--- a/services/input/InputReader.h
+++ b/services/input/InputReader.h
@@ -101,8 +101,8 @@
     nsecs_t pointerGestureMultitouchSettleInterval;
 
     // The transition from PRESS to SWIPE or FREEFORM gesture mode is made when
-    // both of the pointers are moving at least this fast.
-    float pointerGestureMultitouchMinSpeed; // in pixels per second
+    // at least two pointers have moved at least this far from their starting place.
+    float pointerGestureMultitouchMinDistance; // in pixels
 
     // The transition from PRESS to SWIPE gesture mode can only occur when the
     // cosine of the angle between the two vectors is greater than or equal to than this value
@@ -134,7 +134,7 @@
             filterTouchEvents(false),
             filterJumpyTouchEvents(false),
             virtualKeyQuietTime(0),
-            pointerVelocityControlParameters(1.0f, 80.0f, 400.0f, 4.0f),
+            pointerVelocityControlParameters(1.0f, 500.0f, 3000.0f, 3.0f),
             wheelVelocityControlParameters(1.0f, 15.0f, 50.0f, 4.0f),
             pointerGestureQuietInterval(100 * 1000000LL), // 100 ms
             pointerGestureDragMinSwitchSpeed(50), // 50 pixels per second
@@ -142,10 +142,10 @@
             pointerGestureTapDragInterval(150 * 1000000LL), // 150 ms
             pointerGestureTapSlop(10.0f), // 10 pixels
             pointerGestureMultitouchSettleInterval(100 * 1000000LL), // 100 ms
-            pointerGestureMultitouchMinSpeed(150.0f), // 150 pixels per second
+            pointerGestureMultitouchMinDistance(15), // 15 pixels
             pointerGestureSwipeTransitionAngleCosine(0.5f), // cosine of 45degrees
-            pointerGestureSwipeMaxWidthRatio(0.333f),
-            pointerGestureMovementSpeedRatio(0.3f),
+            pointerGestureSwipeMaxWidthRatio(0.25f),
+            pointerGestureMovementSpeedRatio(0.8f),
             pointerGestureZoomSpeedRatio(0.3f) { }
 };
 
@@ -1113,12 +1113,6 @@
         uint32_t lastGestureIdToIndex[MAX_POINTER_ID + 1];
         PointerCoords lastGestureCoords[MAX_POINTERS];
 
-        // Pointer coords and ids for the current spots.
-        PointerControllerInterface::SpotGesture spotGesture;
-        BitSet32 spotIdBits; // same set of ids as touch ids
-        uint32_t spotIdToIndex[MAX_POINTER_ID + 1];
-        PointerCoords spotCoords[MAX_POINTERS];
-
         // Time the pointer gesture last went down.
         nsecs_t downTime;
 
@@ -1165,8 +1159,6 @@
             currentGestureIdBits.clear();
             lastGestureMode = NEUTRAL;
             lastGestureIdBits.clear();
-            spotGesture = PointerControllerInterface::SPOT_GESTURE_NEUTRAL;
-            spotIdBits.clear();
             downTime = 0;
             velocityTracker.clear();
             resetTap();
@@ -1192,7 +1184,6 @@
     void dispatchPointerGestures(nsecs_t when, uint32_t policyFlags, bool isTimeout);
     bool preparePointerGestures(nsecs_t when,
             bool* outCancelPreviousGesture, bool* outFinishPreviousGesture, bool isTimeout);
-    void moveSpotsLocked();
 
     // Dispatches a motion event.
     // If the changedId is >= 0 and the action is POINTER_DOWN or POINTER_UP, the
diff --git a/services/input/PointerController.cpp b/services/input/PointerController.cpp
index eecb76f..5e7713a 100644
--- a/services/input/PointerController.cpp
+++ b/services/input/PointerController.cpp
@@ -240,15 +240,15 @@
     }
 }
 
-void PointerController::setSpots(SpotGesture spotGesture,
-        const PointerCoords* spotCoords, const uint32_t* spotIdToIndex, BitSet32 spotIdBits) {
+void PointerController::setSpots(const PointerCoords* spotCoords,
+        const uint32_t* spotIdToIndex, BitSet32 spotIdBits) {
 #if DEBUG_POINTER_UPDATES
-    LOGD("setSpots: spotGesture=%d", spotGesture);
+    LOGD("setSpots: idBits=%08x", spotIdBits.value);
     for (BitSet32 idBits(spotIdBits); !idBits.isEmpty(); ) {
         uint32_t id = idBits.firstMarkedBit();
         idBits.clearBit(id);
         const PointerCoords& c = spotCoords[spotIdToIndex[id]];
-        LOGD("  spot %d: position=(%0.3f, %0.3f), pressure=%0.3f", id,
+        LOGD(" spot %d: position=(%0.3f, %0.3f), pressure=%0.3f", id,
                 c.getAxisValue(AMOTION_EVENT_AXIS_X),
                 c.getAxisValue(AMOTION_EVENT_AXIS_Y),
                 c.getAxisValue(AMOTION_EVENT_AXIS_PRESSURE));
diff --git a/services/input/PointerController.h b/services/input/PointerController.h
index d6e58c2..9879ec4 100644
--- a/services/input/PointerController.h
+++ b/services/input/PointerController.h
@@ -90,38 +90,6 @@
     /* Sets the mode of the pointer controller. */
     virtual void setPresentation(Presentation presentation) = 0;
 
-    // Describes the current gesture.
-    enum SpotGesture {
-        // No gesture.
-        // Do not display any spots.
-        SPOT_GESTURE_NEUTRAL,
-        // Tap at current location.
-        // Briefly display one spot at the tapped location.
-        SPOT_GESTURE_TAP,
-        // Drag at current location.
-        // Display spot at pressed location.
-        SPOT_GESTURE_DRAG,
-        // Button pressed but no finger is down.
-        // Display spot at pressed location.
-        SPOT_GESTURE_BUTTON_CLICK,
-        // Button pressed and a finger is down.
-        // Display spot at pressed location.
-        SPOT_GESTURE_BUTTON_DRAG,
-        // One finger down and hovering.
-        // Display spot at the hovered location.
-        SPOT_GESTURE_HOVER,
-        // Two fingers down but not sure in which direction they are moving so we consider
-        // it a press at the pointer location.
-        // Display two spots near the pointer location.
-        SPOT_GESTURE_PRESS,
-        // Two fingers down and moving in same direction.
-        // Display two spots near the pointer location.
-        SPOT_GESTURE_SWIPE,
-        // Two or more fingers down and moving in arbitrary directions.
-        // Display two or more spots near the pointer location, one for each finger.
-        SPOT_GESTURE_FREEFORM,
-    };
-
     /* Sets the spots for the current gesture.
      * The spots are not subject to the inactivity timeout like the pointer
      * itself it since they are expected to remain visible for so long as
@@ -131,8 +99,7 @@
      * For spotCoords, pressure != 0 indicates that the spot's location is being
      * pressed (not hovering).
      */
-    virtual void setSpots(SpotGesture spotGesture,
-            const PointerCoords* spotCoords, const uint32_t* spotIdToIndex,
+    virtual void setSpots(const PointerCoords* spotCoords, const uint32_t* spotIdToIndex,
             BitSet32 spotIdBits) = 0;
 
     /* Removes all spots. */
@@ -198,8 +165,8 @@
     virtual void unfade(Transition transition);
 
     virtual void setPresentation(Presentation presentation);
-    virtual void setSpots(SpotGesture spotGesture,
-            const PointerCoords* spotCoords, const uint32_t* spotIdToIndex, BitSet32 spotIdBits);
+    virtual void setSpots(const PointerCoords* spotCoords,
+            const uint32_t* spotIdToIndex, BitSet32 spotIdBits);
     virtual void clearSpots();
 
     void setDisplaySize(int32_t width, int32_t height);
diff --git a/services/input/tests/InputReader_test.cpp b/services/input/tests/InputReader_test.cpp
index e85ae1f..aef9fd8 100644
--- a/services/input/tests/InputReader_test.cpp
+++ b/services/input/tests/InputReader_test.cpp
@@ -101,8 +101,8 @@
     virtual void setPresentation(Presentation presentation) {
     }
 
-    virtual void setSpots(SpotGesture spotGesture,
-            const PointerCoords* spotCoords, const uint32_t* spotIdToIndex, BitSet32 spotIdBits) {
+    virtual void setSpots(const PointerCoords* spotCoords,
+            const uint32_t* spotIdToIndex, BitSet32 spotIdBits) {
     }
 
     virtual void clearSpots() {
diff --git a/services/java/com/android/server/WifiService.java b/services/java/com/android/server/WifiService.java
index 6acc32f..9e0f26c 100644
--- a/services/java/com/android/server/WifiService.java
+++ b/services/java/com/android/server/WifiService.java
@@ -235,6 +235,15 @@
                     }
                     break;
                 }
+                case AsyncChannel.CMD_CHANNEL_DISCONNECTED: {
+                    if (msg.arg1 == AsyncChannel.STATUS_SEND_UNSUCCESSFUL) {
+                        Slog.d(TAG, "Send failed, client connection lost");
+                    } else {
+                        Slog.d(TAG, "Client connection lost with reason: " + msg.arg1);
+                    }
+                    mClients.remove((AsyncChannel) msg.obj);
+                    break;
+                }
                 case AsyncChannel.CMD_CHANNEL_FULL_CONNECTION: {
                     AsyncChannel ac = new AsyncChannel();
                     ac.connect(mContext, this, msg.replyTo);
@@ -312,6 +321,13 @@
                     }
                     break;
                 }
+                case AsyncChannel.CMD_CHANNEL_DISCONNECTED: {
+                    Slog.e(TAG, "WifiStateMachine channel lost, msg.arg1 =" + msg.arg1);
+                    mWifiStateMachineChannel = null;
+                    //Re-establish connection to state machine
+                    mWsmChannel.connect(mContext, this, mWifiStateMachine.getHandler());
+                    break;
+                }
                 default: {
                     Slog.d(TAG, "WifiStateMachineHandler.handleMessage ignoring msg=" + msg);
                     break;
@@ -584,7 +600,12 @@
      */
     public WifiConfiguration getWifiApConfiguration() {
         enforceAccessPermission();
-        return mWifiStateMachine.syncGetWifiApConfiguration(mWifiStateMachineChannel);
+        if (mWifiStateMachineChannel != null) {
+            return mWifiStateMachine.syncGetWifiApConfiguration(mWifiStateMachineChannel);
+        } else {
+            Slog.e(TAG, "mWifiStateMachineChannel is not initialized");
+            return null;
+        }
     }
 
     /**
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 4cc032f..c503fb8 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -90,7 +90,6 @@
 import android.os.FileUtils;
 import android.os.Handler;
 import android.os.IBinder;
-import android.os.IInterface;
 import android.os.IPermissionController;
 import android.os.Looper;
 import android.os.Message;
diff --git a/services/java/com/android/server/wm/InputManager.java b/services/java/com/android/server/wm/InputManager.java
index 4eda684..3b01217 100644
--- a/services/java/com/android/server/wm/InputManager.java
+++ b/services/java/com/android/server/wm/InputManager.java
@@ -540,8 +540,13 @@
         }
 
         @SuppressWarnings("unused")
-        public int getTapTimeout() {
-            return ViewConfiguration.getTapTimeout();
+        public int getHoverTapTimeout() {
+            return ViewConfiguration.getHoverTapTimeout();
+        }
+
+        @SuppressWarnings("unused")
+        public int getHoverTapSlop() {
+            return ViewConfiguration.getHoverTapSlop();
         }
 
         @SuppressWarnings("unused")
@@ -555,11 +560,6 @@
         }
 
         @SuppressWarnings("unused")
-        public int getTouchSlop() {
-            return ViewConfiguration.get(mContext).getScaledTouchSlop();
-        }
-
-        @SuppressWarnings("unused")
         public int getMaxEventsPerSecond() {
             int result = 0;
             try {
diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java
index 4ff6b06..9291182 100644
--- a/services/java/com/android/server/wm/WindowManagerService.java
+++ b/services/java/com/android/server/wm/WindowManagerService.java
@@ -153,6 +153,7 @@
     static final boolean DEBUG_WINDOW_MOVEMENT = false;
     static final boolean DEBUG_TOKEN_MOVEMENT = false;
     static final boolean DEBUG_ORIENTATION = false;
+    static final boolean DEBUG_APP_ORIENTATION = false;
     static final boolean DEBUG_CONFIGURATION = false;
     static final boolean DEBUG_APP_TRANSITIONS = false;
     static final boolean DEBUG_STARTING_WINDOW = false;
@@ -427,6 +428,7 @@
     boolean mWindowsFreezingScreen = false;
     long mFreezeGcPending = 0;
     int mAppsFreezingScreen = 0;
+    int mLastWindowForcedOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
 
     int mLayoutSeq = 0;
     
@@ -3187,6 +3189,15 @@
     }
 
     public int getOrientationFromWindowsLocked() {
+        if (mDisplayFrozen || mOpeningApps.size() > 0 || mClosingApps.size() > 0) {
+            // If the display is frozen, some activities may be in the middle
+            // of restarting, and thus have removed their old window.  If the
+            // window has the flag to hide the lock screen, then the lock screen
+            // can re-appear and inflict its own orientation on us.  Keep the
+            // orientation stable until this all settles down.
+            return mLastWindowForcedOrientation;
+        }
+
         int pos = mWindows.size() - 1;
         while (pos >= 0) {
             WindowState wtoken = mWindows.get(pos);
@@ -3194,7 +3205,7 @@
             if (wtoken.mAppToken != null) {
                 // We hit an application window. so the orientation will be determined by the
                 // app window. No point in continuing further.
-                return ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
+                return (mLastWindowForcedOrientation=ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
             }
             if (!wtoken.isVisibleLw() || !wtoken.mPolicyVisibilityAfterAnim) {
                 continue;
@@ -3204,10 +3215,10 @@
                     (req == ActivityInfo.SCREEN_ORIENTATION_BEHIND)){
                 continue;
             } else {
-                return req;
+                return (mLastWindowForcedOrientation=req);
             }
         }
-        return ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
+        return (mLastWindowForcedOrientation=ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
     }
 
     public int getOrientationFromAppTokensLocked() {
@@ -3220,16 +3231,23 @@
         while (pos >= 0) {
             AppWindowToken wtoken = mAppTokens.get(pos);
             pos--;
+
+            if (DEBUG_APP_ORIENTATION) Slog.v(TAG, "Checking app orientation: " + wtoken);
+
             // if we're about to tear down this window and not seek for
             // the behind activity, don't use it for orientation
             if (!findingBehind
                     && (!wtoken.hidden && wtoken.hiddenRequested)) {
+                if (DEBUG_ORIENTATION) Slog.v(TAG, "Skipping " + wtoken
+                        + " -- going to hide");
                 continue;
             }
 
             if (!haveGroup) {
                 // We ignore any hidden applications on the top.
                 if (wtoken.hiddenRequested || wtoken.willBeHidden) {
+                    if (DEBUG_ORIENTATION) Slog.v(TAG, "Skipping " + wtoken
+                            + " -- hidden on top");
                     continue;
                 }
                 haveGroup = true;
@@ -3243,6 +3261,8 @@
                 // user's orientation.
                 if (lastOrientation != ActivityInfo.SCREEN_ORIENTATION_BEHIND
                         && lastFullscreen) {
+                    if (DEBUG_ORIENTATION) Slog.v(TAG, "Done at " + wtoken
+                            + " -- end of group, return " + lastOrientation);
                     return lastOrientation;
                 }
             }
@@ -3253,16 +3273,21 @@
             lastFullscreen = wtoken.appFullscreen;
             if (lastFullscreen
                     && or != ActivityInfo.SCREEN_ORIENTATION_BEHIND) {
+                if (DEBUG_ORIENTATION) Slog.v(TAG, "Done at " + wtoken
+                        + " -- full screen, return " + or);
                 return or;
             }
             // If this application has requested an explicit orientation,
             // then use it.
             if (or != ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED
                     && or != ActivityInfo.SCREEN_ORIENTATION_BEHIND) {
+                if (DEBUG_ORIENTATION) Slog.v(TAG, "Done at " + wtoken
+                        + " -- explicitly set, return " + or);
                 return or;
             }
             findingBehind |= (or == ActivityInfo.SCREEN_ORIENTATION_BEHIND);
         }
+        if (DEBUG_ORIENTATION) Slog.v(TAG, "No app is requesting an orientation");
         return ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
     }
 
@@ -3335,15 +3360,6 @@
      * android.os.IBinder)
      */
     boolean updateOrientationFromAppTokensLocked(boolean inTransaction) {
-        if (mDisplayFrozen || mOpeningApps.size() > 0 || mClosingApps.size() > 0) {
-            // If the display is frozen, some activities may be in the middle
-            // of restarting, and thus have removed their old window.  If the
-            // window has the flag to hide the lock screen, then the lock screen
-            // can re-appear and inflict its own orientation on us.  Keep the
-            // orientation stable until this all settles down.
-            return false;
-        }
-
         boolean changed = false;
         long ident = Binder.clearCallingIdentity();
         try {
@@ -8934,9 +8950,10 @@
                     pw.print(" mAppsFreezingScreen="); pw.print(mAppsFreezingScreen);
                     pw.print(" mWaitingForConfig="); pw.println(mWaitingForConfig);
             pw.print("  mRotation="); pw.print(mRotation);
-                    pw.print(" mForcedAppOrientation="); pw.print(mForcedAppOrientation);
                     pw.print(" mRequestedRotation="); pw.print(mRequestedRotation);
                     pw.print(" mAltOrientation="); pw.println(mAltOrientation);
+            pw.print("  mLastWindowForcedOrientation"); pw.print(mLastWindowForcedOrientation);
+                    pw.print(" mForcedAppOrientation="); pw.println(mForcedAppOrientation);
             pw.print("  mDeferredRotation="); pw.print(mDeferredRotation);
                     pw.print(", mDeferredRotationAnimFlags="); pw.println(mDeferredRotationAnimFlags);
             pw.print("  mAnimationPending="); pw.print(mAnimationPending);
diff --git a/services/jni/com_android_server_InputManager.cpp b/services/jni/com_android_server_InputManager.cpp
index 2704647..608ea1a 100644
--- a/services/jni/com_android_server_InputManager.cpp
+++ b/services/jni/com_android_server_InputManager.cpp
@@ -56,7 +56,7 @@
 // The exponent used to calculate the pointer speed scaling factor.
 // The scaling factor is calculated as 2 ^ (speed * exponent),
 // where the speed ranges from -7 to + 7 and is supplied by the user.
-static const float POINTER_SPEED_EXPONENT = 1.0f / 3;
+static const float POINTER_SPEED_EXPONENT = 1.0f / 4;
 
 static struct {
     jclass clazz;
@@ -77,10 +77,10 @@
     jmethodID getKeyRepeatTimeout;
     jmethodID getKeyRepeatDelay;
     jmethodID getMaxEventsPerSecond;
-    jmethodID getTapTimeout;
+    jmethodID getHoverTapTimeout;
+    jmethodID getHoverTapSlop;
     jmethodID getDoubleTapTimeout;
     jmethodID getLongPressTimeout;
-    jmethodID getTouchSlop;
     jmethodID getPointerLayer;
     jmethodID getPointerIcon;
 } gCallbacksClassInfo;
@@ -412,32 +412,32 @@
         env->DeleteLocalRef(excludedDeviceNames);
     }
 
-    jint tapTimeout = env->CallIntMethod(mCallbacksObj,
-            gCallbacksClassInfo.getTapTimeout);
-    if (!checkAndClearExceptionFromCallback(env, "getTapTimeout")) {
+    jint hoverTapTimeout = env->CallIntMethod(mCallbacksObj,
+            gCallbacksClassInfo.getHoverTapTimeout);
+    if (!checkAndClearExceptionFromCallback(env, "getHoverTapTimeout")) {
         jint doubleTapTimeout = env->CallIntMethod(mCallbacksObj,
                 gCallbacksClassInfo.getDoubleTapTimeout);
         if (!checkAndClearExceptionFromCallback(env, "getDoubleTapTimeout")) {
             jint longPressTimeout = env->CallIntMethod(mCallbacksObj,
                     gCallbacksClassInfo.getLongPressTimeout);
             if (!checkAndClearExceptionFromCallback(env, "getLongPressTimeout")) {
-                outConfig->pointerGestureTapInterval = milliseconds_to_nanoseconds(tapTimeout);
+                outConfig->pointerGestureTapInterval = milliseconds_to_nanoseconds(hoverTapTimeout);
 
                 // We must ensure that the tap-drag interval is significantly shorter than
                 // the long-press timeout because the tap is held down for the entire duration
                 // of the double-tap timeout.
                 jint tapDragInterval = max(min(longPressTimeout - 100,
-                        doubleTapTimeout), tapTimeout);
+                        doubleTapTimeout), hoverTapTimeout);
                 outConfig->pointerGestureTapDragInterval =
                         milliseconds_to_nanoseconds(tapDragInterval);
             }
         }
     }
 
-    jint touchSlop = env->CallIntMethod(mCallbacksObj,
-            gCallbacksClassInfo.getTouchSlop);
-    if (!checkAndClearExceptionFromCallback(env, "getTouchSlop")) {
-        outConfig->pointerGestureTapSlop = touchSlop;
+    jint hoverTapSlop = env->CallIntMethod(mCallbacksObj,
+            gCallbacksClassInfo.getHoverTapSlop);
+    if (!checkAndClearExceptionFromCallback(env, "getHoverTapSlop")) {
+        outConfig->pointerGestureTapSlop = hoverTapSlop;
     }
 
     { // acquire lock
@@ -1348,8 +1348,11 @@
     GET_METHOD_ID(gCallbacksClassInfo.getKeyRepeatDelay, gCallbacksClassInfo.clazz,
             "getKeyRepeatDelay", "()I");
 
-    GET_METHOD_ID(gCallbacksClassInfo.getTapTimeout, gCallbacksClassInfo.clazz,
-            "getTapTimeout", "()I");
+    GET_METHOD_ID(gCallbacksClassInfo.getHoverTapTimeout, gCallbacksClassInfo.clazz,
+            "getHoverTapTimeout", "()I");
+
+    GET_METHOD_ID(gCallbacksClassInfo.getHoverTapSlop, gCallbacksClassInfo.clazz,
+            "getHoverTapSlop", "()I");
 
     GET_METHOD_ID(gCallbacksClassInfo.getDoubleTapTimeout, gCallbacksClassInfo.clazz,
             "getDoubleTapTimeout", "()I");
@@ -1357,9 +1360,6 @@
     GET_METHOD_ID(gCallbacksClassInfo.getLongPressTimeout, gCallbacksClassInfo.clazz,
             "getLongPressTimeout", "()I");
 
-    GET_METHOD_ID(gCallbacksClassInfo.getTouchSlop, gCallbacksClassInfo.clazz,
-            "getTouchSlop", "()I");
-
     GET_METHOD_ID(gCallbacksClassInfo.getMaxEventsPerSecond, gCallbacksClassInfo.clazz,
             "getMaxEventsPerSecond", "()I");
 
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 517c335..1d75a7b 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -77,6 +77,10 @@
     }
 }
 
+void Layer::destroy() const {
+    mFlinger->destroyLayer(this);
+}
+
 status_t Layer::setToken(const sp<UserClient>& userClient,
         SharedClient* sharedClient, int32_t token)
 {
@@ -145,18 +149,6 @@
     return sur;
 }
 
-status_t Layer::ditch()
-{
-    // NOTE: Called from the main UI thread
-
-    // the layer is not on screen anymore. free as much resources as possible
-    mFreezeLock.clear();
-
-    Mutex::Autolock _l(mLock);
-    mWidth = mHeight = 0;
-    return NO_ERROR;
-}
-
 status_t Layer::setBuffers( uint32_t w, uint32_t h,
                             PixelFormat format, uint32_t flags)
 {
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 128f93d..278d64e 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -82,7 +82,6 @@
     virtual bool isSecure() const           { return mSecure; }
     virtual bool isProtected() const;
     virtual sp<Surface> createSurface() const;
-    virtual status_t ditch();
     virtual void onRemoved();
 
     // only for debugging
@@ -93,6 +92,7 @@
         return mFreezeLock; }
 
 protected:
+    virtual void destroy() const;
     virtual void dump(String8& result, char* scratch, size_t size) const;
 
 private:
diff --git a/services/surfaceflinger/LayerBase.cpp b/services/surfaceflinger/LayerBase.cpp
index 6025ed4..022f251 100644
--- a/services/surfaceflinger/LayerBase.cpp
+++ b/services/surfaceflinger/LayerBase.cpp
@@ -616,10 +616,7 @@
      */
 
     // destroy client resources
-    sp<LayerBaseClient> layer = getOwner();
-    if (layer != 0) {
-        mFlinger->destroySurface(layer);
-    }
+    mFlinger->destroySurface(mOwner);
 }
 
 sp<LayerBaseClient> LayerBaseClient::Surface::getOwner() const {
diff --git a/services/surfaceflinger/LayerBase.h b/services/surfaceflinger/LayerBase.h
index 7162e47..6c49a19 100644
--- a/services/surfaceflinger/LayerBase.h
+++ b/services/surfaceflinger/LayerBase.h
@@ -202,10 +202,6 @@
      */
     virtual bool isProtected() const   { return false; }
 
-    /** Called from the main thread, when the surface is removed from the
-     * draw list */
-    virtual status_t ditch() { return NO_ERROR; }
-
     /** called with the state lock when the surface is removed from the
      *  current list */
     virtual void onRemoved() { };
@@ -271,7 +267,8 @@
     volatile    int32_t         mInvalidate;
                 
 
-protected:
+public:
+    // called from class SurfaceFlinger
     virtual ~LayerBase();
 
 private:
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index a9fa1ef..9a312a7 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -387,6 +387,9 @@
 {
     waitForEvent();
 
+    // call Layer's destructor
+    handleDestroyLayers();
+
     // check for transactions
     if (UNLIKELY(mConsoleSignals)) {
         handleConsoleEvents();
@@ -395,7 +398,7 @@
     if (LIKELY(mTransactionCount == 0)) {
         // if we're in a global transaction, don't do anything.
         const uint32_t mask = eTransactionNeeded | eTraversalNeeded;
-        uint32_t transactionFlags = getTransactionFlags(mask);
+        uint32_t transactionFlags = peekTransactionFlags(mask);
         if (LIKELY(transactionFlags)) {
             handleTransaction(transactionFlags);
         }
@@ -480,39 +483,26 @@
 
 void SurfaceFlinger::handleTransaction(uint32_t transactionFlags)
 {
-    Vector< sp<LayerBase> > ditchedLayers;
+    Mutex::Autolock _l(mStateLock);
+    const nsecs_t now = systemTime();
+    mDebugInTransaction = now;
 
-    /*
-     * Perform and commit the transaction
-     */
+    // Here we're guaranteed that some transaction flags are set
+    // so we can call handleTransactionLocked() unconditionally.
+    // We call getTransactionFlags(), which will also clear the flags,
+    // with mStateLock held to guarantee that mCurrentState won't change
+    // until the transaction is committed.
 
-    { // scope for the lock
-        Mutex::Autolock _l(mStateLock);
-        const nsecs_t now = systemTime();
-        mDebugInTransaction = now;
-        handleTransactionLocked(transactionFlags, ditchedLayers);
-        mLastTransactionTime = systemTime() - now;
-        mDebugInTransaction = 0;
-        invalidateHwcGeometry();
-        // here the transaction has been committed
-    }
+    const uint32_t mask = eTransactionNeeded | eTraversalNeeded;
+    transactionFlags = getTransactionFlags(mask);
+    handleTransactionLocked(transactionFlags);
 
-    /*
-     * Clean-up all layers that went away
-     * (do this without the lock held)
-     */
-
-    const size_t count = ditchedLayers.size();
-    for (size_t i=0 ; i<count ; i++) {
-        if (ditchedLayers[i] != 0) {
-            //LOGD("ditching layer %p", ditchedLayers[i].get());
-            ditchedLayers[i]->ditch();
-        }
-    }
+    mLastTransactionTime = systemTime() - now;
+    mDebugInTransaction = 0;
+    // here the transaction has been committed
 }
 
-void SurfaceFlinger::handleTransactionLocked(
-        uint32_t transactionFlags, Vector< sp<LayerBase> >& ditchedLayers)
+void SurfaceFlinger::handleTransactionLocked(uint32_t transactionFlags)
 {
     const LayerVector& currentLayers(mCurrentState.layersSortedByZ);
     const size_t count = currentLayers.size();
@@ -584,7 +574,6 @@
                 const sp<LayerBase>& layer(previousLayers[i]);
                 if (currentLayers.indexOf( layer ) < 0) {
                     // this layer is not visible anymore
-                    ditchedLayers.add(layer);
                     mDirtyRegionRemovedLayer.orSelf(layer->visibleRegionScreen);
                 }
             }
@@ -594,6 +583,31 @@
     commitTransaction();
 }
 
+void SurfaceFlinger::destroyLayer(LayerBase const* layer)
+{
+    Mutex::Autolock _l(mDestroyedLayerLock);
+    mDestroyedLayers.add(layer);
+    signalEvent();
+}
+
+void SurfaceFlinger::handleDestroyLayers()
+{
+    Vector<LayerBase const *> destroyedLayers;
+
+    { // scope for the lock
+        Mutex::Autolock _l(mDestroyedLayerLock);
+        destroyedLayers = mDestroyedLayers;
+        mDestroyedLayers.clear();
+    }
+
+    // call destructors without a lock held
+    const size_t count = destroyedLayers.size();
+    for (size_t i=0 ; i<count ; i++) {
+        //LOGD("destroying %s", destroyedLayers[i]->getName().string());
+        delete destroyedLayers[i];
+    }
+}
+
 sp<FreezeLock> SurfaceFlinger::getFreezeLock() const
 {
     return new FreezeLock(const_cast<SurfaceFlinger *>(this));
@@ -1096,15 +1110,15 @@
 ssize_t SurfaceFlinger::addClientLayer(const sp<Client>& client,
         const sp<LayerBaseClient>& lbc)
 {
-    Mutex::Autolock _l(mStateLock);
-
     // attach this layer to the client
-    ssize_t name = client->attachLayer(lbc);
+    size_t name = client->attachLayer(lbc);
+
+    Mutex::Autolock _l(mStateLock);
 
     // add this layer to the current state list
     addLayer_l(lbc);
 
-    return name;
+    return ssize_t(name);
 }
 
 status_t SurfaceFlinger::removeLayer(const sp<LayerBase>& layer)
@@ -1155,6 +1169,11 @@
     return NO_ERROR;
 }
 
+uint32_t SurfaceFlinger::peekTransactionFlags(uint32_t flags)
+{
+    return android_atomic_release_load(&mTransactionFlags);
+}
+
 uint32_t SurfaceFlinger::getTransactionFlags(uint32_t flags)
 {
     return android_atomic_and(~flags, &mTransactionFlags) & flags;
@@ -1362,51 +1381,18 @@
     return err;
 }
 
-status_t SurfaceFlinger::destroySurface(const sp<LayerBaseClient>& layer)
+status_t SurfaceFlinger::destroySurface(const wp<LayerBaseClient>& layer)
 {
     // called by ~ISurface() when all references are gone
-
-    class MessageDestroySurface : public MessageBase {
-        SurfaceFlinger* flinger;
-        sp<LayerBaseClient> layer;
-    public:
-        MessageDestroySurface(
-                SurfaceFlinger* flinger, const sp<LayerBaseClient>& layer)
-            : flinger(flinger), layer(layer) { }
-        virtual bool handler() {
-            sp<LayerBaseClient> l(layer);
-            layer.clear(); // clear it outside of the lock;
-            Mutex::Autolock _l(flinger->mStateLock);
-            /*
-             * remove the layer from the current list -- chances are that it's
-             * not in the list anyway, because it should have been removed
-             * already upon request of the client (eg: window manager).
-             * However, a buggy client could have not done that.
-             * Since we know we don't have any more clients, we don't need
-             * to use the purgatory.
-             */
-            status_t err = flinger->removeLayer_l(l);
-            if (err == NAME_NOT_FOUND) {
-                // The surface wasn't in the current list, which means it was
-                // removed already, which means it is in the purgatory,
-                // and need to be removed from there.
-                // This needs to happen from the main thread since its dtor
-                // must run from there (b/c of OpenGL ES). Additionally, we
-                // can't really acquire our internal lock from
-                // destroySurface() -- see postMessage() below.
-                ssize_t idx = flinger->mLayerPurgatory.remove(l);
-                LOGE_IF(idx < 0,
-                        "layer=%p is not in the purgatory list", l.get());
-            }
-
-            LOGE_IF(err<0 && err != NAME_NOT_FOUND,
-                    "error removing layer=%p (%s)", l.get(), strerror(-err));
-            return true;
-        }
-    };
-
-    postMessageAsync( new MessageDestroySurface(this, layer) );
-    return NO_ERROR;
+    status_t err = NO_ERROR;
+    sp<LayerBaseClient> l(layer.promote());
+    if (l != NULL) {
+        Mutex::Autolock _l(mStateLock);
+        err = removeLayer_l(l);
+        LOGE_IF(err<0 && err != NAME_NOT_FOUND,
+                "error removing layer=%p (%s)", l.get(), strerror(-err));
+    }
+    return err;
 }
 
 status_t SurfaceFlinger::setClientState(
@@ -2381,15 +2367,17 @@
     return NO_ERROR;
 }
 
-ssize_t Client::attachLayer(const sp<LayerBaseClient>& layer)
+size_t Client::attachLayer(const sp<LayerBaseClient>& layer)
 {
-    int32_t name = android_atomic_inc(&mNameGenerator);
+    Mutex::Autolock _l(mLock);
+    size_t name = mNameGenerator++;
     mLayers.add(name, layer);
     return name;
 }
 
 void Client::detachLayer(const LayerBaseClient* layer)
 {
+    Mutex::Autolock _l(mLock);
     // we do a linear search here, because this doesn't happen often
     const size_t count = mLayers.size();
     for (size_t i=0 ; i<count ; i++) {
@@ -2399,9 +2387,11 @@
         }
     }
 }
-sp<LayerBaseClient> Client::getLayerUser(int32_t i) const {
+sp<LayerBaseClient> Client::getLayerUser(int32_t i) const
+{
+    Mutex::Autolock _l(mLock);
     sp<LayerBaseClient> lbc;
-    const wp<LayerBaseClient>& layer(mLayers.valueFor(i));
+    wp<LayerBaseClient> layer(mLayers.valueFor(i));
     if (layer != 0) {
         lbc = layer.promote();
         LOGE_IF(lbc==0, "getLayerUser(name=%d) is dead", int(i));
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 9566819..f81b074 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -65,7 +65,7 @@
     status_t initCheck() const;
 
     // protected by SurfaceFlinger::mStateLock
-    ssize_t attachLayer(const sp<LayerBaseClient>& layer);
+    size_t attachLayer(const sp<LayerBaseClient>& layer);
     void detachLayer(const LayerBaseClient* layer);
     sp<LayerBaseClient> getLayerUser(int32_t i) const;
 
@@ -81,9 +81,15 @@
     virtual status_t destroySurface(SurfaceID surfaceId);
     virtual status_t setState(int32_t count, const layer_state_t* states);
 
-    DefaultKeyedVector< size_t, wp<LayerBaseClient> > mLayers;
+    // constant
     sp<SurfaceFlinger> mFlinger;
-    int32_t mNameGenerator;
+
+    // protected by mLock
+    DefaultKeyedVector< size_t, wp<LayerBaseClient> > mLayers;
+    size_t mNameGenerator;
+
+    // thread-safe
+    mutable Mutex mLock;
 };
 
 class UserClient : public BnSurfaceComposerClient
@@ -227,6 +233,7 @@
     status_t addLayer(const sp<LayerBase>& layer);
     status_t invalidateLayerVisibility(const sp<LayerBase>& layer);
     void invalidateHwcGeometry();
+    void destroyLayer(LayerBase const* layer);
 
     sp<Layer> getLayer(const sp<ISurface>& sur) const;
 
@@ -254,7 +261,7 @@
             uint32_t w, uint32_t h, uint32_t flags);
 
     status_t removeSurface(const sp<Client>& client, SurfaceID sid);
-    status_t destroySurface(const sp<LayerBaseClient>& layer);
+    status_t destroySurface(const wp<LayerBaseClient>& layer);
     status_t setClientState(const sp<Client>& client,
             int32_t count, const layer_state_t* states);
 
@@ -299,9 +306,8 @@
 private:
             void        handleConsoleEvents();
             void        handleTransaction(uint32_t transactionFlags);
-            void        handleTransactionLocked(
-                            uint32_t transactionFlags, 
-                            Vector< sp<LayerBase> >& ditchedLayers);
+            void        handleTransactionLocked(uint32_t transactionFlags);
+            void        handleDestroyLayers();
 
             void        computeVisibleRegions(
                             LayerVector& currentLayers,
@@ -324,6 +330,7 @@
             status_t    purgatorizeLayer_l(const sp<LayerBase>& layer);
 
             uint32_t    getTransactionFlags(uint32_t flags);
+            uint32_t    peekTransactionFlags(uint32_t flags);
             uint32_t    setTransactionFlags(uint32_t flags);
             void        commitTransaction();
 
@@ -422,6 +429,11 @@
                 // these are thread safe
     mutable     Barrier                     mReadyToRunBarrier;
 
+
+                // protected by mDestroyedLayerLock;
+    mutable     Mutex                       mDestroyedLayerLock;
+                Vector<LayerBase const *>   mDestroyedLayers;
+
                 // atomic variables
                 enum {
                     eConsoleReleased = 1,
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 8732e21..acbf08b 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -426,8 +426,7 @@
     public static final int NETWORK_TYPE_LTE = 13;
     /** Current network is eHRPD */
     public static final int NETWORK_TYPE_EHRPD = 14;
-    /** Current network is HSPA+
-     * @hide */
+    /** Current network is HSPA+ */
     public static final int NETWORK_TYPE_HSPAP = 15;
 
     /**
@@ -450,6 +449,7 @@
      * @see #NETWORK_TYPE_IDEN
      * @see #NETWORK_TYPE_LTE
      * @see #NETWORK_TYPE_EHRPD
+     * @see #NETWORK_TYPE_HSPAP
      */
     public int getNetworkType() {
         try{
@@ -506,6 +506,8 @@
                 return "CDMA - eHRPD";
             case NETWORK_TYPE_IDEN:
                 return "iDEN";
+            case NETWORK_TYPE_HSPAP:
+                return "HSPA+";
             default:
                 return "UNKNOWN";
         }
diff --git a/telephony/java/com/android/internal/telephony/BaseCommands.java b/telephony/java/com/android/internal/telephony/BaseCommands.java
index e1d8c85..13afbb7 100644
--- a/telephony/java/com/android/internal/telephony/BaseCommands.java
+++ b/telephony/java/com/android/internal/telephony/BaseCommands.java
@@ -97,8 +97,10 @@
     protected Registrant mRestrictedStateRegistrant;
     protected Registrant mGsmBroadcastSmsRegistrant;
 
-    // Network Mode received from PhoneFactory
-    protected int mNetworkMode;
+    // Preferred network type received from PhoneFactory.
+    // This is used when establishing a connection to the
+    // vendor ril so it starts up in the correct mode.
+    protected int mPreferredNetworkType;
     // CDMA subscription received from PhoneFactory
     protected int mCdmaSubscription;
     // Type of Phone, GSM or CDMA. Set by CDMAPhone or GSMPhone.
diff --git a/telephony/java/com/android/internal/telephony/RIL.java b/telephony/java/com/android/internal/telephony/RIL.java
index f9f641c..40a396e 100644
--- a/telephony/java/com/android/internal/telephony/RIL.java
+++ b/telephony/java/com/android/internal/telephony/RIL.java
@@ -612,14 +612,14 @@
 
     //***** Constructors
 
-    public RIL(Context context, int networkMode, int cdmaSubscription) {
+    public RIL(Context context, int preferredNetworkType, int cdmaSubscription) {
         super(context);
         if (RILJ_LOGD) {
-            riljLog("RIL(context, networkMode=" + networkMode +
+            riljLog("RIL(context, preferredNetworkType=" + preferredNetworkType +
                     " cdmaSubscription=" + cdmaSubscription + ")");
         }
         mCdmaSubscription  = cdmaSubscription;
-        mNetworkMode = networkMode;
+        mPreferredNetworkType = preferredNetworkType;
         mPhoneType = RILConstants.NO_PHONE;
 
         PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
@@ -1814,6 +1814,8 @@
         rr.mp.writeInt(1);
         rr.mp.writeInt(networkType);
 
+        mPreferredNetworkType = networkType;
+
         if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)
                 + " : " + networkType);
 
@@ -2223,7 +2225,7 @@
             case RIL_REQUEST_STK_HANDLE_CALL_SETUP_REQUESTED_FROM_SIM: ret =  responseInts(p); break;
             case RIL_REQUEST_EXPLICIT_CALL_TRANSFER: ret =  responseVoid(p); break;
             case RIL_REQUEST_SET_PREFERRED_NETWORK_TYPE: ret =  responseVoid(p); break;
-            case RIL_REQUEST_GET_PREFERRED_NETWORK_TYPE: ret =  responseInts(p); break;
+            case RIL_REQUEST_GET_PREFERRED_NETWORK_TYPE: ret =  responseGetPreferredNetworkType(p); break;
             case RIL_REQUEST_GET_NEIGHBORING_CELL_IDS: ret = responseCellList(p); break;
             case RIL_REQUEST_SET_LOCATION_UPDATES: ret =  responseVoid(p); break;
             case RIL_REQUEST_CDMA_SET_SUBSCRIPTION_SOURCE: ret =  responseVoid(p); break;
@@ -2738,7 +2740,7 @@
 
                 // Initial conditions
                 setRadioPower(false, null);
-                setPreferredNetworkType(mNetworkMode, null);
+                setPreferredNetworkType(mPreferredNetworkType, null);
                 setCdmaSubscriptionSource(mCdmaSubscription, null);
                 notifyRegistrantsRilConnectionChanged(((int[])ret)[0]);
                 break;
@@ -3162,6 +3164,18 @@
        return response;
     }
 
+    private Object responseGetPreferredNetworkType(Parcel p) {
+       int [] response = (int[]) responseInts(p);
+
+       if (response.length >= 1) {
+           // Since this is the response for getPreferredNetworkType
+           // we'll assume that it should be the value we want the
+           // vendor ril to take if we reestablish a connection to it.
+           mPreferredNetworkType = response[0];
+       }
+       return response;
+    }
+
     private Object responseGmsBroadcastConfig(Parcel p) {
         int num;
         ArrayList<SmsBroadcastConfigInfo> response;
diff --git a/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java
index 922cd4c..8e3ed93 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java
@@ -425,7 +425,7 @@
         AffineTransform matrixTx = matrixDelegate.getAffineTransform();
 
         // combine them so that the given matrix is applied after.
-        currentTx.preConcatenate(matrixTx);
+        currentTx.concatenate(matrixTx);
 
         // give it to the graphics2D as a new matrix replacing all previous transform
         snapshot.setTransform(currentTx);
@@ -717,7 +717,7 @@
     /*package*/ static void native_drawCircle(int nativeCanvas,
             float cx, float cy, float radius, int paint) {
         native_drawOval(nativeCanvas,
-                new RectF(cx - radius, cy - radius, radius*2, radius*2),
+                new RectF(cx - radius, cy - radius, radius, radius),
                 paint);
     }
 
diff --git a/tools/layoutlib/bridge/src/android/os/HandlerThread_Delegate.java b/tools/layoutlib/bridge/src/android/os/HandlerThread_Delegate.java
new file mode 100644
index 0000000..afbe97c0
--- /dev/null
+++ b/tools/layoutlib/bridge/src/android/os/HandlerThread_Delegate.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2011 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 android.os;
+
+import com.android.layoutlib.bridge.android.BridgeContext;
+import com.android.layoutlib.bridge.impl.RenderAction;
+import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Delegate overriding selected methods of android.os.HandlerThread
+ *
+ * Through the layoutlib_create tool, selected methods of Handler have been replaced
+ * by calls to methods of the same name in this delegate class.
+ *
+ *
+ */
+public class HandlerThread_Delegate {
+
+    private static Map<BridgeContext, List<HandlerThread>> sThreads =
+            new HashMap<BridgeContext, List<HandlerThread>>();
+
+    public static void cleanUp(BridgeContext context) {
+        List<HandlerThread> list = sThreads.get(context);
+        if (list != null) {
+            for (HandlerThread thread : list) {
+                thread.quit();
+            }
+
+            list.clear();
+            sThreads.remove(context);
+        }
+    }
+
+    // -------- Delegate methods
+
+    @LayoutlibDelegate
+    /*package*/ static void run(HandlerThread theThread) {
+        // record the thread so that it can be quit() on clean up.
+        BridgeContext context = RenderAction.getCurrentContext();
+        List<HandlerThread> list = sThreads.get(context);
+        if (list == null) {
+            list = new ArrayList<HandlerThread>();
+            sThreads.put(context, list);
+        }
+
+        list.add(theThread);
+
+        // ---- START DEFAULT IMPLEMENTATION.
+
+        theThread.mTid = Process.myTid();
+        Looper.prepare();
+        synchronized (theThread) {
+            theThread.mLooper = Looper.myLooper();
+            theThread.notifyAll();
+        }
+        Process.setThreadPriority(theThread.mPriority);
+        theThread.onLooperPrepared();
+        Looper.loop();
+        theThread.mTid = -1;
+    }
+}
diff --git a/tools/layoutlib/bridge/src/android/view/LayoutInflater_Delegate.java b/tools/layoutlib/bridge/src/android/view/LayoutInflater_Delegate.java
index 0f3cf57..3ef3288 100644
--- a/tools/layoutlib/bridge/src/android/view/LayoutInflater_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/view/LayoutInflater_Delegate.java
@@ -22,7 +22,10 @@
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
 
+import android.content.res.TypedArray;
+import android.content.res.XmlResourceParser;
 import android.util.AttributeSet;
+import android.util.Xml;
 
 import java.io.IOException;
 
@@ -35,6 +38,8 @@
  */
 public class LayoutInflater_Delegate {
 
+    public static boolean sIsInInclude = false;
+
     /**
      * Recursive method used to descend down the xml hierarchy and instantiate
      * views, instantiate their children, and then call onFinishInflate().
@@ -94,4 +99,128 @@
             }
         }
     }
+
+    @LayoutlibDelegate
+    public static void parseInclude(
+            LayoutInflater thisInflater,
+            XmlPullParser parser, View parent, AttributeSet attrs)
+            throws XmlPullParserException, IOException {
+
+        int type;
+
+        if (parent instanceof ViewGroup) {
+            final int layout = attrs.getAttributeResourceValue(null, "layout", 0);
+            if (layout == 0) {
+                final String value = attrs.getAttributeValue(null, "layout");
+                if (value == null) {
+                    throw new InflateException("You must specifiy a layout in the"
+                            + " include tag: <include layout=\"@layout/layoutID\" />");
+                } else {
+                    throw new InflateException("You must specifiy a valid layout "
+                            + "reference. The layout ID " + value + " is not valid.");
+                }
+            } else {
+                final XmlResourceParser childParser =
+                    thisInflater.getContext().getResources().getLayout(layout);
+
+                try {
+                    final AttributeSet childAttrs = Xml.asAttributeSet(childParser);
+
+                    while ((type = childParser.next()) != XmlPullParser.START_TAG &&
+                            type != XmlPullParser.END_DOCUMENT) {
+                        // Empty.
+                    }
+
+                    if (type != XmlPullParser.START_TAG) {
+                        throw new InflateException(childParser.getPositionDescription() +
+                                ": No start tag found!");
+                    }
+
+                    final String childName = childParser.getName();
+
+                    if (LayoutInflater.TAG_MERGE.equals(childName)) {
+                        // Inflate all children.
+                        thisInflater.rInflate(childParser, parent, childAttrs, false);
+                    } else {
+                        final View view = thisInflater.createViewFromTag(parent, childName, childAttrs);
+                        final ViewGroup group = (ViewGroup) parent;
+
+                        // We try to load the layout params set in the <include /> tag. If
+                        // they don't exist, we will rely on the layout params set in the
+                        // included XML file.
+                        // During a layoutparams generation, a runtime exception is thrown
+                        // if either layout_width or layout_height is missing. We catch
+                        // this exception and set localParams accordingly: true means we
+                        // successfully loaded layout params from the <include /> tag,
+                        // false means we need to rely on the included layout params.
+                        ViewGroup.LayoutParams params = null;
+                        try {
+                            // ---- START CHANGES
+                            sIsInInclude = true;
+                            // ---- END CHANGES
+
+                            params = group.generateLayoutParams(attrs);
+
+                        } catch (RuntimeException e) {
+                            // ---- START CHANGES
+                            sIsInInclude = false;
+                            // ---- END CHANGES
+
+                            params = group.generateLayoutParams(childAttrs);
+                        } finally {
+                            // ---- START CHANGES
+                            sIsInInclude = false;
+                            // ---- END CHANGES
+
+                            if (params != null) {
+                                view.setLayoutParams(params);
+                            }
+                        }
+
+                        // Inflate all children.
+                        thisInflater.rInflate(childParser, view, childAttrs, true);
+
+                        // Attempt to override the included layout's android:id with the
+                        // one set on the <include /> tag itself.
+                        TypedArray a = thisInflater.mContext.obtainStyledAttributes(attrs,
+                            com.android.internal.R.styleable.View, 0, 0);
+                        int id = a.getResourceId(com.android.internal.R.styleable.View_id, View.NO_ID);
+                        // While we're at it, let's try to override android:visibility.
+                        int visibility = a.getInt(com.android.internal.R.styleable.View_visibility, -1);
+                        a.recycle();
+
+                        if (id != View.NO_ID) {
+                            view.setId(id);
+                        }
+
+                        switch (visibility) {
+                            case 0:
+                                view.setVisibility(View.VISIBLE);
+                                break;
+                            case 1:
+                                view.setVisibility(View.INVISIBLE);
+                                break;
+                            case 2:
+                                view.setVisibility(View.GONE);
+                                break;
+                        }
+
+                        group.addView(view);
+                    }
+                } finally {
+                    childParser.close();
+                }
+            }
+        } else {
+            throw new InflateException("<include /> can only be used inside of a ViewGroup");
+        }
+
+        final int currentDepth = parser.getDepth();
+        while (((type = parser.next()) != XmlPullParser.END_TAG ||
+                parser.getDepth() > currentDepth) && type != XmlPullParser.END_DOCUMENT) {
+            // Empty
+        }
+    }
+
+
 }
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java
index 144ec42..3ba3257 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java
@@ -196,7 +196,7 @@
                 Capability.UNBOUND_RENDERING,
                 Capability.CUSTOM_BACKGROUND_COLOR,
                 Capability.RENDER,
-                //Capability.LAYOUT_ONLY, // disable to run on ADT 10.0 which doesn't include this.
+                Capability.LAYOUT_ONLY,
                 Capability.EMBEDDED_LAYOUT,
                 Capability.VIEW_MANIPULATION,
                 Capability.PLAY_ANIMATION,
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
index e536028..4fa924d 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
@@ -71,7 +71,6 @@
 import java.io.FileInputStream;
 import java.io.FileNotFoundException;
 import java.io.FileOutputStream;
-import java.io.FileReader;
 import java.io.IOException;
 import java.io.InputStream;
 import java.util.HashMap;
@@ -342,7 +341,7 @@
                 try {
                     KXmlParser parser = new KXmlParser();
                     parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true);
-                    parser.setInput(new FileReader(xml));
+                    parser.setInput(new FileInputStream(xml), "UTF-8"); //$NON-NLS-1$);
 
                     // set the resource ref to have correct view cookies
                     mBridgeInflater.setResourceReference(resource);
@@ -514,14 +513,13 @@
         BridgeTypedArray ta = ((BridgeResources) mSystemResources).newTypeArray(attrs.length,
                 isPlatformFile);
 
-        // resolve the defStyleAttr value into a IStyleResourceValue
-        StyleResourceValue defStyleValues = null;
-
         // look for a custom style.
         String customStyle = null;
         if (set != null) {
             customStyle = set.getAttributeValue(null /* namespace*/, "style");
         }
+
+        StyleResourceValue customStyleValues = null;
         if (customStyle != null) {
             ResourceValue item = mRenderResources.findResValue(customStyle,
                     false /*forceFrameworkOnly*/);
@@ -530,75 +528,76 @@
             item = mRenderResources.resolveResValue(item);
 
             if (item instanceof StyleResourceValue) {
-                defStyleValues = (StyleResourceValue)item;
+                customStyleValues = (StyleResourceValue)item;
             }
         }
 
-        if (defStyleValues == null) {
-            if (defStyleAttr != 0) {
-                // get the name from the int.
-                String defStyleName = searchAttr(defStyleAttr);
+        // resolve the defStyleAttr value into a IStyleResourceValue
+        StyleResourceValue defStyleValues = null;
 
-                if (defaultPropMap != null) {
-                    defaultPropMap.put("style", defStyleName);
+        if (defStyleAttr != 0) {
+            // get the name from the int.
+            String defStyleName = searchAttr(defStyleAttr);
+
+            if (defaultPropMap != null) {
+                defaultPropMap.put("style", defStyleName);
+            }
+
+            // look for the style in the current theme, and its parent:
+            ResourceValue item = mRenderResources.findItemInTheme(defStyleName);
+
+            if (item != null) {
+                // item is a reference to a style entry. Search for it.
+                item = mRenderResources.findResValue(item.getValue(),
+                        false /*forceFrameworkOnly*/);
+
+                if (item instanceof StyleResourceValue) {
+                    defStyleValues = (StyleResourceValue)item;
                 }
+            } else {
+                Bridge.getLog().error(null,
+                        String.format(
+                                "Failed to find style '%s' in current theme", defStyleName),
+                        null /*data*/);
+            }
+        } else if (defStyleRes != 0) {
+            Pair<ResourceType, String> value = Bridge.resolveResourceId(defStyleRes);
+            if (value == null) {
+                value = mProjectCallback.resolveResourceId(defStyleRes);
+            }
 
-                // look for the style in the current theme, and its parent:
-                ResourceValue item = mRenderResources.findItemInTheme(defStyleName);
-
-                if (item != null) {
-                    // item is a reference to a style entry. Search for it.
-                    item = mRenderResources.findResValue(item.getValue(),
-                            false /*forceFrameworkOnly*/);
-
-                    if (item instanceof StyleResourceValue) {
-                        defStyleValues = (StyleResourceValue)item;
-                    }
-                } else {
-                    Bridge.getLog().error(null,
-                            String.format(
-                                    "Failed to find style '%s' in current theme", defStyleName),
-                            null /*data*/);
-                }
-            } else if (defStyleRes != 0) {
-                Pair<ResourceType, String> value = Bridge.resolveResourceId(defStyleRes);
-                if (value == null) {
-                    value = mProjectCallback.resolveResourceId(defStyleRes);
-                }
-
-                if (value != null) {
-                    if (value.getFirst() == ResourceType.STYLE) {
-                        // look for the style in the current theme, and its parent:
-                        ResourceValue item = mRenderResources.findItemInTheme(value.getSecond());
-                        if (item != null) {
-                            if (item instanceof StyleResourceValue) {
-                                if (defaultPropMap != null) {
-                                    defaultPropMap.put("style", item.getName());
-                                }
-
-                                defStyleValues = (StyleResourceValue)item;
+            if (value != null) {
+                if (value.getFirst() == ResourceType.STYLE) {
+                    // look for the style in the current theme, and its parent:
+                    ResourceValue item = mRenderResources.findItemInTheme(value.getSecond());
+                    if (item != null) {
+                        if (item instanceof StyleResourceValue) {
+                            if (defaultPropMap != null) {
+                                defaultPropMap.put("style", item.getName());
                             }
-                        } else {
-                            Bridge.getLog().error(null,
-                                    String.format(
-                                            "Style with id 0x%x (resolved to '%s') does not exist.",
-                                            defStyleRes, value.getSecond()),
-                                    null /*data*/);
+
+                            defStyleValues = (StyleResourceValue)item;
                         }
                     } else {
                         Bridge.getLog().error(null,
                                 String.format(
-                                        "Resouce id 0x%x is not of type STYLE (instead %s)",
-                                        defStyleRes, value.getFirst().toString()),
+                                        "Style with id 0x%x (resolved to '%s') does not exist.",
+                                        defStyleRes, value.getSecond()),
                                 null /*data*/);
                     }
                 } else {
                     Bridge.getLog().error(null,
                             String.format(
-                                    "Failed to find style with id 0x%x in current theme",
-                                    defStyleRes),
+                                    "Resouce id 0x%x is not of type STYLE (instead %s)",
+                                    defStyleRes, value.getFirst().toString()),
                             null /*data*/);
                 }
+            } else {
+                Bridge.getLog().error(null,
+                        String.format(
+                                "Failed to find style with id 0x%x in current theme",
+                                defStyleRes),
+                        null /*data*/);
             }
         }
 
@@ -623,8 +622,13 @@
                 if (value == null) {
                     ResourceValue resValue = null;
 
-                    // look for the value in the defStyle first (and its parent if needed)
-                    if (defStyleValues != null) {
+                    // look for the value in the custom style first (and its parent if needed)
+                    if (customStyleValues != null) {
+                        resValue = mRenderResources.findItemInStyle(customStyleValues, name);
+                    }
+
+                    // then look for the value in the default Style (and its parent if needed)
+                    if (resValue == null && defStyleValues != null) {
                         resValue = mRenderResources.findItemInStyle(defStyleValues, name);
                     }
 
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeInflater.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeInflater.java
index d6bbebd..7c90a31 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeInflater.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeInflater.java
@@ -36,7 +36,7 @@
 import android.view.ViewGroup;
 
 import java.io.File;
-import java.io.FileReader;
+import java.io.FileInputStream;
 
 /**
  * Custom implementation of {@link LayoutInflater} to handle custom views.
@@ -177,7 +177,7 @@
                     try {
                         KXmlParser parser = new KXmlParser();
                         parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true);
-                        parser.setInput(new FileReader(f));
+                        parser.setInput(new FileInputStream(f), "UTF-8"); //$NON-NLS-1$
 
                         BridgeXmlBlockParser bridgeParser = new BridgeXmlBlockParser(
                                 parser, bridgeContext, false);
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeResources.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeResources.java
index 273e493..345f053 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeResources.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeResources.java
@@ -46,7 +46,6 @@
 import java.io.File;
 import java.io.FileInputStream;
 import java.io.FileNotFoundException;
-import java.io.FileReader;
 import java.io.InputStream;
 
 /**
@@ -244,7 +243,7 @@
                         // give that to our XmlBlockParser
                         parser = new KXmlParser();
                         parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true);
-                        parser.setInput(new FileReader(xml));
+                        parser.setInput(new FileInputStream(xml), "UTF-8"); //$NON-NLS-1$);
                     }
                 }
 
@@ -282,7 +281,7 @@
                     // give that to our XmlBlockParser
                     parser = new KXmlParser();
                     parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true);
-                    parser.setInput(new FileReader(xml));
+                    parser.setInput(new FileInputStream(xml), "UTF-8"); //$NON-NLS-1$);
 
                     return new BridgeXmlBlockParser(parser, mContext, mPlatformResourceFlag[0]);
                 }
@@ -501,7 +500,7 @@
                     try {
                         KXmlParser parser = new KXmlParser();
                         parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true);
-                        parser.setInput(new FileReader(f));
+                        parser.setInput(new FileInputStream(f), "UTF-8"); //$NON-NLS-1$);
 
                         return new BridgeXmlBlockParser(parser, mContext, mPlatformResourceFlag[0]);
                     } catch (XmlPullParserException e) {
@@ -536,7 +535,7 @@
         try {
             KXmlParser parser = new KXmlParser();
             parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true);
-            parser.setInput(new FileReader(f));
+            parser.setInput(new FileInputStream(f), "UTF-8"); //$NON-NLS-1$);
 
             return new BridgeXmlBlockParser(parser, mContext, mPlatformResourceFlag[0]);
         } catch (XmlPullParserException e) {
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeTypedArray.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeTypedArray.java
index b9f769f..d4600a1 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeTypedArray.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeTypedArray.java
@@ -36,10 +36,11 @@
 import android.graphics.drawable.Drawable;
 import android.util.DisplayMetrics;
 import android.util.TypedValue;
+import android.view.LayoutInflater_Delegate;
 import android.view.ViewGroup.LayoutParams;
 
 import java.io.File;
-import java.io.FileReader;
+import java.io.FileInputStream;
 import java.util.Arrays;
 import java.util.Map;
 
@@ -315,7 +316,7 @@
             try {
                 KXmlParser parser = new KXmlParser();
                 parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true);
-                parser.setInput(new FileReader(f));
+                parser.setInput(new FileInputStream(f), "UTF-8"); //$NON-NLS-1$);
 
                 BridgeXmlBlockParser blockParser = new BridgeXmlBlockParser(
                         parser, mContext, resValue.isFramework());
@@ -471,40 +472,23 @@
      */
     @Override
     public int getDimensionPixelSize(int index, int defValue) {
-        if (mResourceData[index] == null) {
+        try {
+            return getDimension(index);
+        } catch (RuntimeException e) {
+            if (mResourceData[index] != null) {
+                String s = mResourceData[index].getValue();
+
+                if (s != null) {
+                    // looks like we were unable to resolve the dimension value
+                    Bridge.getLog().warning(LayoutLog.TAG_RESOURCES_FORMAT,
+                            String.format(
+                                "\"%1$s\" in attribute \"%2$s\" is not a valid format.",
+                                s, mNames[index]), null /*data*/);
+                }
+            }
+
             return defValue;
         }
-
-        String s = mResourceData[index].getValue();
-
-        if (s == null) {
-            return defValue;
-        } else if (s.equals(BridgeConstants.MATCH_PARENT) ||
-                s.equals(BridgeConstants.FILL_PARENT)) {
-            return LayoutParams.MATCH_PARENT;
-        } else if (s.equals(BridgeConstants.WRAP_CONTENT)) {
-            return LayoutParams.WRAP_CONTENT;
-        } else if (RenderResources.REFERENCE_NULL.equals(s)) {
-            return defValue;
-        }
-
-        if (ResourceHelper.stringToFloat(s, mValue)) {
-            float f = mValue.getDimension(mBridgeResources.mMetrics);
-
-            final int res = (int)(f+0.5f);
-            if (res != 0) return res;
-            if (f == 0) return 0;
-            if (f > 0) return 1;
-            return defValue; // this is basically unreachable.
-        }
-
-        // looks like we were unable to resolve the dimension value
-        Bridge.getLog().warning(LayoutLog.TAG_RESOURCES_FORMAT,
-                String.format(
-                    "\"%1$s\" in attribute \"%2$s\" is not a valid format.",
-                    s, mNames[index]), null /*data*/);
-
-        return defValue;
     }
 
     /**
@@ -521,7 +505,20 @@
      */
     @Override
     public int getLayoutDimension(int index, String name) {
-        return getDimensionPixelSize(index, 0);
+        try {
+            // this will throw an exception
+            return getDimension(index);
+        } catch (RuntimeException e) {
+
+            if (LayoutInflater_Delegate.sIsInInclude) {
+                throw new RuntimeException();
+            }
+
+            Bridge.getLog().warning(LayoutLog.TAG_RESOURCES_FORMAT,
+                    "You must supply a " + name + " attribute.", null);
+
+            return 0;
+        }
     }
 
     @Override
@@ -529,6 +526,36 @@
         return getDimensionPixelSize(index, defValue);
     }
 
+    private int getDimension(int index) {
+        if (mResourceData[index] == null) {
+            throw new RuntimeException();
+        }
+
+        String s = mResourceData[index].getValue();
+
+        if (s == null) {
+            throw new RuntimeException();
+        } else if (s.equals(BridgeConstants.MATCH_PARENT) ||
+                s.equals(BridgeConstants.FILL_PARENT)) {
+            return LayoutParams.MATCH_PARENT;
+        } else if (s.equals(BridgeConstants.WRAP_CONTENT)) {
+            return LayoutParams.WRAP_CONTENT;
+        } else if (RenderResources.REFERENCE_NULL.equals(s)) {
+            throw new RuntimeException();
+        }
+
+        if (ResourceHelper.stringToFloat(s, mValue)) {
+            float f = mValue.getDimension(mBridgeResources.mMetrics);
+
+            final int res = (int)(f+0.5f);
+            if (res != 0) return res;
+            if (f == 0) return 0;
+            if (f > 0) return 1;
+        }
+
+        throw new RuntimeException();
+    }
+
     /**
      * Retrieve a fractional unit attribute at <var>index</var>.
      *
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/CustomBar.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/CustomBar.java
index 0c4b0d3..060e6ee 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/CustomBar.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/CustomBar.java
@@ -73,7 +73,7 @@
         parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true);
         parser.setInput(
                 getClass().getResourceAsStream(layoutPath),
-                "UTF8");
+                "UTF8"); //$NON-NLS-1$
 
         BridgeXmlBlockParser bridgeParser = new BridgeXmlBlockParser(
                 parser, (BridgeContext) context, false /*platformFile*/);
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderAction.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderAction.java
index 8e80c21..6194f5d 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderAction.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderAction.java
@@ -29,6 +29,7 @@
 import com.android.layoutlib.bridge.android.BridgeContext;
 import com.android.resources.ResourceType;
 
+import android.os.HandlerThread_Delegate;
 import android.util.DisplayMetrics;
 
 import java.util.concurrent.TimeUnit;
@@ -228,6 +229,10 @@
     private void tearDown() {
         // Make sure to remove static references, otherwise we could not unload the lib
         mContext.disposeResources();
+
+        // quit HandlerThread created during this session.
+        HandlerThread_Delegate.cleanUp(sCurrentContext);
+
         sCurrentContext = null;
 
         Bridge.setLog(null);
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/ResourceHelper.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/ResourceHelper.java
index 96ab30f..e5efa4e 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/ResourceHelper.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/ResourceHelper.java
@@ -44,7 +44,6 @@
 
 import java.io.File;
 import java.io.FileInputStream;
-import java.io.FileReader;
 import java.io.IOException;
 import java.io.InputStream;
 import java.net.MalformedURLException;
@@ -124,7 +123,7 @@
                     // providing an XmlPullParser
                     KXmlParser parser = new KXmlParser();
                     parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true);
-                    parser.setInput(new FileReader(f));
+                    parser.setInput(new FileInputStream(f), "UTF-8"); //$NON-NLS-1$);
 
                     BridgeXmlBlockParser blockParser = new BridgeXmlBlockParser(
                             parser, context, resValue.isFramework());
@@ -206,7 +205,7 @@
                     // let the framework inflate the Drawable from the XML file.
                     KXmlParser parser = new KXmlParser();
                     parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true);
-                    parser.setInput(new FileReader(f));
+                    parser.setInput(new FileInputStream(f), "UTF-8"); //$NON-NLS-1$);
 
                     BridgeXmlBlockParser blockParser = new BridgeXmlBlockParser(
                             parser, context, value.isFramework());
diff --git a/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/android/BridgeXmlBlockParserTest.java b/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/android/BridgeXmlBlockParserTest.java
index 3252fb49..70d5446 100644
--- a/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/android/BridgeXmlBlockParserTest.java
+++ b/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/android/BridgeXmlBlockParserTest.java
@@ -44,7 +44,7 @@
 
         InputStream input = this.getClass().getClassLoader().getResourceAsStream(
             "com/android/layoutlib/testdata/layout1.xml");
-        parser.setInput(input, null /*encoding*/);
+        parser.setInput(input, "UTF-8"); //$NON-NLS-1$
 
         assertEquals(XmlPullParser.START_DOCUMENT, parser.next());
 
diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java
index eff6bbc..5c60318 100644
--- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java
+++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java
@@ -99,8 +99,10 @@
         "android.content.res.Resources$Theme#resolveAttribute",
         "android.graphics.BitmapFactory#finishDecode",
         "android.os.Handler#sendMessageAtTime",
+        "android.os.HandlerThread#run",
         "android.os.Build#getString",
         "android.view.LayoutInflater#rInflate",
+        "android.view.LayoutInflater#parseInclude",
         "android.view.View#isInEditMode",
         "com.android.internal.util.XmlUtils#convertValueToInt",
         // TODO: comment out once DelegateClass is working