Merge "Change user 0 directory back for compatibility"
diff --git a/api/current.txt b/api/current.txt
index 2514efdb..a71c8666 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -1828,6 +1828,7 @@
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator CREATOR;
     field public static final int DEFAULT = 1; // 0x1
+    field public static final int FEEDBACK_ALL_MASK = -1; // 0xffffffff
     field public static final int FEEDBACK_AUDIBLE = 4; // 0x4
     field public static final int FEEDBACK_GENERIC = 16; // 0x10
     field public static final int FEEDBACK_HAPTIC = 2; // 0x2
@@ -16710,7 +16711,7 @@
     field public static final java.lang.String SELECTED_INPUT_METHOD_SUBTYPE = "selected_input_method_subtype";
     field public static final java.lang.String SETTINGS_CLASSNAME = "settings_classname";
     field public static final java.lang.String SYS_PROP_SETTING_VERSION = "sys.settings_secure_version";
-    field public static final java.lang.String TOUCH_EXPLORATION_REQUESTED = "touch_exploration_requested";
+    field public static final java.lang.String TOUCH_EXPLORATION_ENABLED = "touch_exploration_enabled";
     field public static final java.lang.String TTS_DEFAULT_COUNTRY = "tts_default_country";
     field public static final java.lang.String TTS_DEFAULT_LANG = "tts_default_lang";
     field public static final java.lang.String TTS_DEFAULT_PITCH = "tts_default_pitch";
@@ -17951,7 +17952,7 @@
     method public abstract android.view.textservice.SuggestionsInfo getSuggestions(android.view.textservice.TextInfo, int, java.lang.String);
     method public android.view.textservice.SuggestionsInfo[] getSuggestionsMultiple(android.view.textservice.TextInfo[], java.lang.String, int, boolean);
     method public final android.os.IBinder onBind(android.content.Intent);
-    field public static final java.lang.String SERVICE_INTERFACE;
+    field public static final java.lang.String SERVICE_INTERFACE = "android.service.textservice.SpellCheckerService";
   }
 
   public class SpellCheckerSession {
@@ -22232,6 +22233,7 @@
     method public final android.view.View findViewWithTag(java.lang.Object);
     method public void findViewsWithText(java.util.ArrayList<android.view.View>, java.lang.CharSequence);
     method protected boolean fitSystemWindows(android.graphics.Rect);
+    method public boolean fitsSystemWindows();
     method public android.view.View focusSearch(int);
     method public void forceLayout();
     method public float getAlpha();
@@ -22473,6 +22475,7 @@
     method public void setEnabled(boolean);
     method public void setFadingEdgeLength(int);
     method public void setFilterTouchesWhenObscured(boolean);
+    method public void setFitsSystemWindows(boolean);
     method public void setFocusable(boolean);
     method public void setFocusableInTouchMode(boolean);
     method public void setHapticFeedbackEnabled(boolean);
@@ -24055,6 +24058,8 @@
     method public android.content.ComponentName getComponent();
     method public java.lang.String getId();
     method public java.lang.String getPackageName();
+    method public android.graphics.drawable.Drawable loadIcon(android.content.pm.PackageManager);
+    method public java.lang.CharSequence loadLabel(android.content.pm.PackageManager);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator CREATOR;
   }
@@ -26196,7 +26201,7 @@
     method public int timePassed();
   }
 
-  public class SearchView extends android.widget.LinearLayout {
+  public class SearchView extends android.widget.LinearLayout implements android.view.CollapsibleActionView {
     ctor public SearchView(android.content.Context);
     ctor public SearchView(android.content.Context, android.util.AttributeSet);
     method public java.lang.CharSequence getQuery();
@@ -26205,6 +26210,8 @@
     method public boolean isIconified();
     method public boolean isQueryRefinementEnabled();
     method public boolean isSubmitButtonEnabled();
+    method public void onActionViewCollapsed();
+    method public void onActionViewExpanded();
     method public void setIconified(boolean);
     method public void setIconifiedByDefault(boolean);
     method public void setMaxWidth(int);
diff --git a/core/java/android/accessibilityservice/AccessibilityServiceInfo.java b/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
index a09607a..41a3eaca 100644
--- a/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
+++ b/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
@@ -75,6 +75,17 @@
     public static final int FEEDBACK_GENERIC = 0x0000010;
 
     /**
+     * Mask for all feedback types.
+     *
+     * @see #FEEDBACK_SPOKEN
+     * @see #FEEDBACK_HAPTIC
+     * @see #FEEDBACK_AUDIBLE
+     * @see #FEEDBACK_VISUAL
+     * @see #FEEDBACK_GENERIC
+     */
+    public static final int FEEDBACK_ALL_MASK = 0xFFFFFFFF;
+
+    /**
      * If an {@link AccessibilityService} is the default for a given type.
      * Default service is invoked only if no package specific one exists. In case of
      * more than one package specific service only the earlier registered is notified.
diff --git a/core/java/android/content/pm/Signature.java b/core/java/android/content/pm/Signature.java
index d4e5cc1..b32664e 100644
--- a/core/java/android/content/pm/Signature.java
+++ b/core/java/android/content/pm/Signature.java
@@ -45,16 +45,23 @@
      * {@link #toChars} or {@link #toCharsString()}.
      */
     public Signature(String text) {
-        final int N = text.length()/2;
-        byte[] sig = new byte[N];
-        for (int i=0; i<N; i++) {
-            char c = text.charAt(i*2);
-            byte b = (byte)(
-                    (c >= 'a' ? (c - 'a' + 10) : (c - '0'))<<4);
-            c = text.charAt(i*2 + 1);
-            b |= (byte)(c >= 'a' ? (c - 'a' + 10) : (c - '0'));
-            sig[i] = b;
+        final byte[] input = text.getBytes();
+        final int N = input.length;
+        final byte[] sig = new byte[N / 2];
+        int sigIndex = 0;
+
+        for (int i = 0; i < N;) {
+            int b;
+
+            final int hi = input[i++];
+            b = (hi >= 'a' ? (hi - 'a' + 10) : (hi - '0')) << 4;
+
+            final int lo = input[i++];
+            b |= (lo >= 'a' ? (lo - 'a' + 10) : (lo - '0')) & 0x0F;
+
+            sig[sigIndex++] = (byte) (b & 0xFF);
         }
+
         mSignature = sig;
     }
 
diff --git a/core/java/android/provider/CallLog.java b/core/java/android/provider/CallLog.java
index 382fcf3..e23d6f3 100644
--- a/core/java/android/provider/CallLog.java
+++ b/core/java/android/provider/CallLog.java
@@ -184,6 +184,16 @@
         public static final String VOICEMAIL_URI = "voicemail_uri";
 
         /**
+         * Whether this item has been read or otherwise consumed by the user.
+         * <p>
+         * Unlike the {@link #NEW} field, which requires the user to have acknowledged the
+         * existence of the entry, this implies the user has interacted with the entry.
+         * <P>Type: INTEGER (boolean)</P>
+         * @hide
+         */
+        public static final String IS_READ = "is_read";
+
+        /**
          * Adds a call to the call log.
          *
          * @param ci the CallerInfo object to get the target contact from.  Can be null
diff --git a/core/java/android/provider/ContactsContract.java b/core/java/android/provider/ContactsContract.java
index 4a719ec..a0f1eec 100644
--- a/core/java/android/provider/ContactsContract.java
+++ b/core/java/android/provider/ContactsContract.java
@@ -6514,6 +6514,32 @@
         public static final String SUMMARY_COUNT = "summ_count";
 
         /**
+         * A boolean query parameter that can be used with {@link Groups#CONTENT_SUMMARY_URI}.
+         * It will additionally return {@link #SUMMARY_GROUP_COUNT_PER_ACCOUNT}.
+         *
+         * @hide
+         */
+        public static final String PARAM_RETURN_GROUP_COUNT_PER_ACCOUNT =
+                "return_group_count_per_account";
+
+        /**
+         * The total number of groups of the account that a group belongs to.
+         * This column is available only when the parameter
+         * {@link #PARAM_RETURN_GROUP_COUNT_PER_ACCOUNT} is specified in
+         * {@link Groups#CONTENT_SUMMARY_URI}.
+         *
+         * For example, when the account "A" has two groups "group1" and "group2", and the account
+         * "B" has a group "group3", the rows for "group1" and "group2" return "2" and the row for
+         * "group3" returns "1" for this column.
+         *
+         * Note: This counts only non-favorites, non-auto-add, and not deleted groups.
+         *
+         * Type: INTEGER
+         * @hide
+         */
+        public static final String SUMMARY_GROUP_COUNT_PER_ACCOUNT = "group_count_per_account";
+
+        /**
          * The total number of {@link Contacts} that have both
          * {@link CommonDataKinds.GroupMembership} in this group, and also have phone numbers.
          * Read-only value that is only present when querying
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 1cd46de..cd4e32e 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -2688,11 +2688,9 @@
         public static final String ACCESSIBILITY_ENABLED = "accessibility_enabled";
 
         /**
-         * If touch exploration is requested. Touch exploration is enabled if it is
-         * requested by this setting, accessibility is enabled and there is at least
-         * one enabled accessibility serivce that provides spoken feedback.
+         * If touch exploration is enabled.
          */
-        public static final String TOUCH_EXPLORATION_REQUESTED = "touch_exploration_requested";
+        public static final String TOUCH_EXPLORATION_ENABLED = "touch_exploration_enabled";
 
         /**
          * List of the enabled accessibility providers.
@@ -3935,6 +3933,10 @@
         /** Timeout in milliseconds to wait for NTP server. {@hide} */
         public static final String NTP_TIMEOUT = "ntp_timeout";
 
+        /** Autofill server address (Used in WebView/browser). {@hide} */
+        public static final String WEB_AUTOFILL_QUERY_URL =
+            "web_autofill_query_url";
+
         /**
          * @hide
          */
diff --git a/core/java/android/provider/VoicemailContract.java b/core/java/android/provider/VoicemailContract.java
index 2ad7395..2e5a495 100644
--- a/core/java/android/provider/VoicemailContract.java
+++ b/core/java/android/provider/VoicemailContract.java
@@ -128,6 +128,12 @@
          */
         public static final String NEW = Calls.NEW;
         /**
+         * Whether this item has been read or otherwise consumed by the user.
+         * <P>Type: INTEGER (boolean)</P>
+         * @hide
+         */
+        public static final String IS_READ = Calls.IS_READ;
+        /**
          * The mail box state of the voicemail. This field is currently not used by the system.
          * <P> Possible values: {@link #STATE_INBOX}, {@link #STATE_DELETED},
          * {@link #STATE_UNDELETED}.
diff --git a/core/java/android/server/BluetoothAdapterStateMachine.java b/core/java/android/server/BluetoothAdapterStateMachine.java
new file mode 100644
index 0000000..ae91465
--- /dev/null
+++ b/core/java/android/server/BluetoothAdapterStateMachine.java
@@ -0,0 +1,513 @@
+/*
+ * 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.server;
+
+import android.bluetooth.BluetoothAdapter;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Binder;
+import android.os.Message;
+import android.provider.Settings;
+import android.util.Log;
+
+import com.android.internal.util.IState;
+import com.android.internal.util.State;
+import com.android.internal.util.StateMachine;
+
+import java.io.PrintWriter;
+
+/**
+ * Bluetooth Adapter StateMachine
+ * All the states are at the same level, ie, no hierarchy.
+ *                         (BluetootOn)
+ *                           |    ^
+ *                 TURN_OFF  |    |  BECOME_PAIRABLE
+ *         AIRPLANE_MODE_ON  |    |
+ *                           V    |
+ *                         (Switching)
+ *                           |    ^
+ *     BECOME_NON_PAIRABLE&  |    | TURN_ON(_CONTINUE)/TURN_ON_FOR_PRIVILEGED
+ * ALL_DEVICES_DISCONNECTED  |    |
+ *                           V    |
+ *                          (HotOff)
+ *                           /    ^
+ *                          /     |  SERVICE_RECORD_LOADED
+ *                         |      |
+ *              TURN_COLD  |   (Warmup)
+ *                         \      ^
+ *                          \     |  TURN_HOT/TURN_ON
+ *                           |    |  AIRPLANE_MODE_OFF(when Bluetooth was on before)
+ *                           V    |
+ *                           (PowerOff)   <----- initial state
+ *
+ */
+final class BluetoothAdapterStateMachine extends StateMachine {
+    private static final String TAG = "BluetoothAdapterStateMachine";
+    private static final boolean DBG = false;
+
+    // Message(what) to take an action
+    //
+    // We get this message when user tries to turn on BT
+    public static final int USER_TURN_ON = 1;
+    // We get this message when user tries to turn off BT
+    public static final int USER_TURN_OFF = 2;
+
+    // Message(what) to report a event that the state machine need to respond to
+    //
+    // Event indicates sevice records have been loaded
+    public static final int SERVICE_RECORD_LOADED = 51;
+    // Event indicates all the remote Bluetooth devices has been disconnected
+    public static final int ALL_DEVICES_DISCONNECTED = 52;
+    // Event indicates the Bluetooth is connectable
+    public static final int BECOME_PAIRABLE = 53;
+    // Event indicates the Bluetooth is non-connectable.
+    public static final int BECOME_NON_PAIRABLE = 54;
+    // Event indicates airplane mode is turned on
+    public static final int AIRPLANE_MODE_ON = 55;
+    // Event indicates airplane mode is turned off
+    public static final int AIRPLANE_MODE_OFF = 56;
+
+    // private internal messages
+    //
+    // Turn on Bluetooth Module, Load firmware, and do all the preparation
+    // needed to get the Bluetooth Module ready but keep it not discoverable
+    // and not connectable. This way the Bluetooth Module can be quickly
+    // switched on if needed
+    private static final int TURN_HOT = 101;
+    // USER_TURN_ON is changed to TURN_ON_CONTINUE after we broadcast the
+    // state change intent so that we will not broadcast the intent again in
+    // other state
+    private static final int TURN_ON_CONTINUE = 102;
+    // Unload firmware, turning off Bluetooth module power
+    private static final int TURN_COLD = 103;
+    // For NFC, turn on bluetooth for certain process
+    private static final int TURN_ON_FOR_PRIVILEGED = 104;
+
+    private Context mContext;
+    private BluetoothService mBluetoothService;
+    private BluetoothEventLoop mEventLoop;
+
+    private BluetoothOn mBluetoothOn;
+    private Switching mSwitching;
+    private HotOff mHotOff;
+    private WarmUp mWarmUp;
+    private PowerOff mPowerOff;
+
+    // this is the BluetoothAdapter state that reported externally
+    private int mPublicState;
+
+    BluetoothAdapterStateMachine(Context context, BluetoothService bluetoothService,
+                                 BluetoothAdapter bluetoothAdapter) {
+        super(TAG);
+        mContext = context;
+        mBluetoothService = bluetoothService;
+        mEventLoop = new BluetoothEventLoop(context, bluetoothAdapter, bluetoothService, this);
+
+        mBluetoothOn = new BluetoothOn();
+        mSwitching = new Switching();
+        mHotOff = new HotOff();
+        mWarmUp = new WarmUp();
+        mPowerOff = new PowerOff();
+
+        addState(mBluetoothOn);
+        addState(mSwitching);
+        addState(mHotOff);
+        addState(mWarmUp);
+        addState(mPowerOff);
+        setInitialState(mPowerOff);
+        mPublicState = BluetoothAdapter.STATE_OFF;
+
+        if (mContext.getResources().getBoolean
+            (com.android.internal.R.bool.config_bluetooth_adapter_quick_switch)) {
+            sendMessage(TURN_HOT);
+        }
+    }
+
+    /**
+     * Bluetooth module's power is off, firmware is not loaded.
+     */
+    private class PowerOff extends State {
+        private boolean mPersistSwitchOn = false;
+
+        @Override
+        public void enter() {
+            if (DBG) log("Enter PowerOff: " + mPersistSwitchOn);
+            mPersistSwitchOn = false;
+        }
+        @Override
+        public boolean processMessage(Message message) {
+            if (DBG) log("PowerOff process message: " + message.what);
+
+            boolean retValue = HANDLED;
+            switch(message.what) {
+                case USER_TURN_ON:
+                    // starts turning on BT module, broadcast this out
+                    transitionTo(mWarmUp);
+                    broadcastState(BluetoothAdapter.STATE_TURNING_ON);
+                    if (prepareBluetooth()) {
+                        // this is user request, save the setting
+                        if ((Boolean) message.obj) {
+                            mPersistSwitchOn = true;
+                        }
+                        // We will continue turn the BT on all the way to the BluetoothOn state
+                        deferMessage(obtainMessage(TURN_ON_CONTINUE));
+                    } else {
+                        Log.e(TAG, "failed to prepare bluetooth, abort turning on");
+                        transitionTo(mPowerOff);
+                        broadcastState(BluetoothAdapter.STATE_OFF);
+                    }
+                    break;
+                case TURN_HOT:
+                    if (prepareBluetooth()) {
+                        transitionTo(mWarmUp);
+                    }
+                    break;
+                case AIRPLANE_MODE_OFF:
+                    if (getBluetoothPersistedSetting()) {
+                        // starts turning on BT module, broadcast this out
+                        transitionTo(mWarmUp);
+                        broadcastState(BluetoothAdapter.STATE_TURNING_ON);
+                        if (prepareBluetooth()) {
+                            // We will continue turn the BT on all the way to the BluetoothOn state
+                            deferMessage(obtainMessage(TURN_ON_CONTINUE));
+                            transitionTo(mWarmUp);
+                        } else {
+                            Log.e(TAG, "failed to prepare bluetooth, abort turning on");
+                            transitionTo(mPowerOff);
+                            broadcastState(BluetoothAdapter.STATE_OFF);
+                        }
+                    }
+                    break;
+                case AIRPLANE_MODE_ON: // ignore
+                case USER_TURN_OFF: // ignore
+                    break;
+                default:
+                    return NOT_HANDLED;
+            }
+            return retValue;
+        }
+
+        /**
+         * Turn on Bluetooth Module, Load firmware, and do all the preparation
+         * needed to get the Bluetooth Module ready but keep it not discoverable
+         * and not connectable.
+         * The last step of this method sets up the local service record DB.
+         * There will be a event reporting the status of the SDP setup.
+         */
+        private boolean prepareBluetooth() {
+            if (mBluetoothService.enableNative() != 0) {
+                return false;
+            }
+
+            // try to start event loop, give 2 attempts
+            int retryCount = 2;
+            boolean eventLoopStarted = false;
+            while ((retryCount-- > 0) && !eventLoopStarted) {
+                mEventLoop.start();
+                // it may take a moment for the other thread to do its
+                // thing.  Check periodically for a while.
+                int pollCount = 5;
+                while ((pollCount-- > 0) && !eventLoopStarted) {
+                    if (mEventLoop.isEventLoopRunning()) {
+                        eventLoopStarted = true;
+                        break;
+                    }
+                    try {
+                        Thread.sleep(100);
+                    } catch (InterruptedException e) {
+                        break;
+                    }
+                }
+            }
+
+            if (!eventLoopStarted) {
+                mBluetoothService.disableNative();
+                return false;
+            }
+
+            // get BluetoothService ready
+            if (!mBluetoothService.prepareBluetooth()) {
+                mEventLoop.stop();
+                mBluetoothService.disableNative();
+                return false;
+            }
+
+            return true;
+        }
+    }
+
+    /**
+     * Turning on Bluetooth module's power, loading firmware, starting
+     * event loop thread to listen on Bluetooth module event changes.
+     */
+    private class WarmUp extends State {
+
+        @Override
+        public void enter() {
+            if (DBG) log("Enter WarmUp");
+        }
+
+        @Override
+        public boolean processMessage(Message message) {
+            if (DBG) log("WarmUp process message: " + message.what);
+
+            boolean retValue = HANDLED;
+            switch(message.what) {
+                case SERVICE_RECORD_LOADED:
+                    transitionTo(mHotOff);
+                    break;
+                case USER_TURN_ON: // handle this at HotOff state
+                case TURN_ON_CONTINUE: // Once in HotOff state, continue turn bluetooth
+                                       // on to the BluetoothOn state
+                case AIRPLANE_MODE_ON:
+                case AIRPLANE_MODE_OFF:
+                    deferMessage(message);
+                    break;
+                case USER_TURN_OFF: // ignore
+                    break;
+                default:
+                    return NOT_HANDLED;
+            }
+            return retValue;
+        }
+
+    }
+
+    /**
+     * Bluetooth Module has powered, firmware loaded, event loop started,
+     * SDP loaded, but the modules stays non-discoverable and
+     * non-connectable.
+     */
+    private class HotOff extends State {
+        private boolean mPersistSwitchOn = false;
+
+        @Override
+        public void enter() {
+            if (DBG) log("Enter HotOff: " + mPersistSwitchOn);
+            mPersistSwitchOn = false;
+        }
+
+        @Override
+        public boolean processMessage(Message message) {
+            if (DBG) log("HotOff process message: " + message.what);
+
+            boolean retValue = HANDLED;
+            switch(message.what) {
+                case USER_TURN_ON:
+                    if ((Boolean) message.obj) {
+                        mPersistSwitchOn = true;
+                    }
+                    // let it fall to TURN_ON_CONTINUE:
+                case TURN_ON_CONTINUE:
+                    mBluetoothService.switchConnectable(true);
+                    transitionTo(mSwitching);
+                    broadcastState(BluetoothAdapter.STATE_TURNING_ON);
+                    break;
+                case AIRPLANE_MODE_ON:
+                case TURN_COLD:
+                    mBluetoothService.shutoffBluetooth();
+                    mEventLoop.stop();
+                    transitionTo(mPowerOff);
+                    // ASSERT no support of config_bluetooth_adapter_quick_switch
+                    broadcastState(BluetoothAdapter.STATE_OFF);
+                    break;
+                case AIRPLANE_MODE_OFF:
+                    if (getBluetoothPersistedSetting()) {
+                        mBluetoothService.switchConnectable(true);
+                        transitionTo(mSwitching);
+                        broadcastState(BluetoothAdapter.STATE_TURNING_ON);
+                    }
+                    break;
+                case USER_TURN_OFF: // ignore
+                    break;
+                default:
+                    return NOT_HANDLED;
+            }
+            return retValue;
+        }
+
+    }
+
+    private class Switching extends State {
+
+        @Override
+        public void enter() {
+            int what = getCurrentMessage().what;
+            if (DBG) log("Enter Switching: " + what);
+        }
+        @Override
+        public boolean processMessage(Message message) {
+            if (DBG) log("Switching process message: " + message.what);
+
+            boolean retValue = HANDLED;
+            switch(message.what) {
+                case BECOME_PAIRABLE:
+                    if (mPowerOff.mPersistSwitchOn || mHotOff.mPersistSwitchOn) {
+                        persistSwitchSetting(true);
+                        mPowerOff.mPersistSwitchOn = mHotOff.mPersistSwitchOn = false;
+                    }
+                    String[] propVal = {"Pairable", mBluetoothService.getProperty("Pairable")};
+                    mEventLoop.onPropertyChanged(propVal);
+
+                    // run bluetooth now that it's turned on
+                    mBluetoothService.runBluetooth();
+                    transitionTo(mBluetoothOn);
+                    broadcastState(BluetoothAdapter.STATE_ON);
+                    break;
+                case BECOME_NON_PAIRABLE:
+                    if (mBluetoothService.getAdapterConnectionState() ==
+                        BluetoothAdapter.STATE_DISCONNECTED) {
+                        transitionTo(mHotOff);
+                        finishSwitchingOff();
+                    }
+                    break;
+                case ALL_DEVICES_DISCONNECTED:
+                    if (mBluetoothService.getScanMode() == BluetoothAdapter.SCAN_MODE_NONE) {
+                        transitionTo(mHotOff);
+                        finishSwitchingOff();
+                    }
+                    break;
+                case USER_TURN_ON:
+                case AIRPLANE_MODE_OFF:
+                case AIRPLANE_MODE_ON:
+                case USER_TURN_OFF:
+                    deferMessage(message);
+                    break;
+                default:
+                    return NOT_HANDLED;
+            }
+            return retValue;
+        }
+
+        private void finishSwitchingOff() {
+            if (mBluetoothOn.mPersistBluetoothOff) {
+                persistSwitchSetting(false);
+                mBluetoothOn.mPersistBluetoothOff = false;
+            }
+            mBluetoothService.finishDisable();
+            if (mContext.getResources().getBoolean
+                (com.android.internal.R.bool.config_bluetooth_adapter_quick_switch)) {
+                broadcastState(BluetoothAdapter.STATE_OFF);
+            } else {
+                deferMessage(obtainMessage(TURN_COLD));
+            }
+        }
+    }
+
+    private class BluetoothOn extends State {
+        private boolean mPersistBluetoothOff = false;
+
+        @Override
+        public void enter() {
+            if (DBG) log("Enter BluetoothOn: " + mPersistBluetoothOff);
+            mPersistBluetoothOff = false;
+        }
+        @Override
+        public boolean processMessage(Message message) {
+            if (DBG) log("BluetoothOn process message: " + message.what);
+
+            boolean retValue = HANDLED;
+            switch(message.what) {
+                case USER_TURN_OFF:
+                    if ((Boolean) message.obj) {
+                        mPersistBluetoothOff = true;
+                    }
+                    // let it fall through to AIRPLANE_MODE_ON
+                case AIRPLANE_MODE_ON:
+                    transitionTo(mSwitching);
+                    broadcastState(BluetoothAdapter.STATE_TURNING_OFF);
+                    mBluetoothService.switchConnectable(false);
+                    mBluetoothService.disconnectDevices();
+                    // we turn all the way to PowerOff with AIRPLANE_MODE_ON
+                    if (message.what == AIRPLANE_MODE_ON) {
+                        deferMessage(obtainMessage(AIRPLANE_MODE_ON));
+                    }
+                    break;
+                case AIRPLANE_MODE_OFF: // ignore
+                case USER_TURN_ON: // ignore
+                    break;
+                default:
+                    return NOT_HANDLED;
+            }
+            return retValue;
+        }
+
+    }
+
+    /**
+     * Return the public BluetoothAdapter state
+     */
+    int getBluetoothAdapterState() {
+        return mPublicState;
+    }
+
+    BluetoothEventLoop getBluetoothEventLoop() {
+        return mEventLoop;
+    }
+
+    private void persistSwitchSetting(boolean setOn) {
+        long origCallerIdentityToken = Binder.clearCallingIdentity();
+        Settings.Secure.putInt(mContext.getContentResolver(),
+                               Settings.Secure.BLUETOOTH_ON,
+                               setOn ? 1 : 0);
+        Binder.restoreCallingIdentity(origCallerIdentityToken);
+    }
+
+    private boolean getBluetoothPersistedSetting() {
+        ContentResolver contentResolver = mContext.getContentResolver();
+        return (Settings.Secure.getInt(contentResolver,
+                                       Settings.Secure.BLUETOOTH_ON, 0) > 0);
+    }
+
+    private void broadcastState(int newState) {
+
+        if (DBG) log("Bluetooth state " + mPublicState + " -> " + newState);
+        if (mPublicState == newState) {
+            return;
+        }
+
+        Intent intent = new Intent(BluetoothAdapter.ACTION_STATE_CHANGED);
+        intent.putExtra(BluetoothAdapter.EXTRA_PREVIOUS_STATE, mPublicState);
+        intent.putExtra(BluetoothAdapter.EXTRA_STATE, newState);
+        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
+        mPublicState = newState;
+
+        mContext.sendBroadcast(intent, BluetoothService.BLUETOOTH_PERM);
+    }
+
+    private void dump(PrintWriter pw) {
+        IState currentState = getCurrentState();
+        if (currentState == mPowerOff) {
+            pw.println("Bluetooth OFF - power down\n");
+        } else if (currentState == mWarmUp) {
+            pw.println("Bluetooth OFF - warm up\n");
+        } else if (currentState == mHotOff) {
+            pw.println("Bluetooth OFF - hot but off\n");
+        } else if (currentState == mSwitching) {
+            pw.println("Bluetooth Switching\n");
+        } else if (currentState == mBluetoothOn) {
+            pw.println("Bluetooth ON\n");
+        } else {
+            pw.println("ERROR: Bluetooth UNKNOWN STATE ");
+        }
+    }
+
+    private static void log(String msg) {
+        Log.d(TAG, msg);
+    }
+}
diff --git a/core/java/android/server/BluetoothEventLoop.java b/core/java/android/server/BluetoothEventLoop.java
index f345a6a..107a2a9 100644
--- a/core/java/android/server/BluetoothEventLoop.java
+++ b/core/java/android/server/BluetoothEventLoop.java
@@ -52,6 +52,7 @@
     private final HashMap<String, Integer> mAuthorizationAgentRequestData;
     private final BluetoothService mBluetoothService;
     private final BluetoothAdapter mAdapter;
+    private final BluetoothAdapterStateMachine mBluetoothState;
     private BluetoothA2dp mA2dp;
     private BluetoothInputDevice mInputDevice;
     private final Context mContext;
@@ -107,9 +108,11 @@
     private static native void classInitNative();
 
     /* package */ BluetoothEventLoop(Context context, BluetoothAdapter adapter,
-            BluetoothService bluetoothService) {
+                                     BluetoothService bluetoothService,
+                                     BluetoothAdapterStateMachine bluetoothState) {
         mBluetoothService = bluetoothService;
         mContext = context;
+        mBluetoothState = bluetoothState;
         mPasskeyAgentRequestData = new HashMap<String, Integer>();
         mAuthorizationAgentRequestData = new HashMap<String, Integer>();
         mAdapter = adapter;
@@ -299,8 +302,8 @@
 
     /**
      * Called by native code on a PropertyChanged signal from
-     * org.bluez.Adapter. This method is also called from Java at
-     * {@link BluetoothService.EnableThread#run()} to set the "Pairable"
+     * org.bluez.Adapter. This method is also called from
+     * {@link BluetoothAdapterStateMachine} to set the "Pairable"
      * property when Bluetooth is enabled.
      *
      * @param propValues a string array containing the key and one or more
@@ -334,6 +337,15 @@
                 return;
 
             adapterProperties.setProperty(name, propValues[1]);
+
+            if (name.equals("Pairable")) {
+                if (pairable.equals("true")) {
+                    mBluetoothState.sendMessage(BluetoothAdapterStateMachine.BECOME_PAIRABLE);
+                } else {
+                    mBluetoothState.sendMessage(BluetoothAdapterStateMachine.BECOME_NON_PAIRABLE);
+                }
+            }
+
             int mode = BluetoothService.bluezStringToScanMode(
                     pairable.equals("true"),
                     discoverable.equals("true"));
diff --git a/core/java/android/server/BluetoothService.java b/core/java/android/server/BluetoothService.java
index d68d8ba..34f1971 100755
--- a/core/java/android/server/BluetoothService.java
+++ b/core/java/android/server/BluetoothService.java
@@ -91,7 +91,7 @@
     private BluetoothPan mPan;
     private boolean mIsAirplaneSensitive;
     private boolean mIsAirplaneToggleable;
-    private int mBluetoothState;
+    private BluetoothAdapterStateMachine mBluetoothState;
     private boolean mRestart = false;  // need to call enable() after disable()
     private boolean mIsDiscovering;
     private int[] mAdapterSdpHandles;
@@ -111,9 +111,8 @@
     private static final String SHARED_PREFERENCE_DOCK_ADDRESS = "dock_bluetooth_address";
     private static final String SHARED_PREFERENCES_NAME = "bluetooth_service_settings";
 
-    private static final int MESSAGE_FINISH_DISABLE = 1;
-    private static final int MESSAGE_UUID_INTENT = 2;
-    private static final int MESSAGE_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY = 3;
+    private static final int MESSAGE_UUID_INTENT = 1;
+    private static final int MESSAGE_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY = 2;
 
     // The time (in millisecs) to delay the pairing attempt after the first
     // auto pairing attempt fails. We use an exponential delay with
@@ -206,7 +205,6 @@
             disableNative();
         }
 
-        mBluetoothState = BluetoothAdapter.STATE_OFF;
         mIsDiscovering = false;
 
         mBondState = new BluetoothBondState(context, this);
@@ -306,7 +304,9 @@
 
     public synchronized void initAfterRegistration() {
         mAdapter = BluetoothAdapter.getDefaultAdapter();
-        mEventLoop = new BluetoothEventLoop(mContext, mAdapter, this);
+        mBluetoothState = new BluetoothAdapterStateMachine(mContext, this, mAdapter);
+        mBluetoothState.start();
+        mEventLoop = mBluetoothState.getBluetoothEventLoop();
     }
 
     public synchronized void initAfterA2dpRegistration() {
@@ -329,16 +329,16 @@
     }
 
     private boolean isEnabledInternal() {
-        return mBluetoothState == BluetoothAdapter.STATE_ON;
+        return (getBluetoothStateInternal() == BluetoothAdapter.STATE_ON);
     }
 
     public int getBluetoothState() {
         mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
-        return mBluetoothState;
+        return getBluetoothStateInternal();
     }
 
     int getBluetoothStateInternal() {
-        return mBluetoothState;
+        return mBluetoothState.getBluetoothAdapterState();
     }
 
     /**
@@ -356,7 +356,9 @@
     public synchronized boolean disable(boolean saveSetting) {
         mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH_ADMIN permission");
 
-        switch (mBluetoothState) {
+        int adapterState = getBluetoothStateInternal();
+
+        switch (adapterState) {
         case BluetoothAdapter.STATE_OFF:
             return true;
         case BluetoothAdapter.STATE_ON:
@@ -364,27 +366,12 @@
         default:
             return false;
         }
-        if (mEnableThread != null && mEnableThread.isAlive()) {
-            return false;
-        }
 
-        setBluetoothState(BluetoothAdapter.STATE_TURNING_OFF);
-
-        if (mAdapterSdpHandles != null) removeReservedServiceRecordsNative(mAdapterSdpHandles);
-        setBluetoothTetheringNative(false, BluetoothPanProfileHandler.NAP_ROLE,
-                BluetoothPanProfileHandler.NAP_BRIDGE);
-
-        // Allow 3 seconds for profiles to gracefully disconnect
-        // TODO: Introduce a callback mechanism so that each profile can notify
-        // BluetoothService when it is done shutting down
-        disconnectDevices();
-
-        mHandler.sendMessageDelayed(
-                mHandler.obtainMessage(MESSAGE_FINISH_DISABLE, saveSetting ? 1 : 0, 0), 3000);
+        mBluetoothState.sendMessage(BluetoothAdapterStateMachine.USER_TURN_OFF, saveSetting);
         return true;
     }
 
-    private synchronized void disconnectDevices() {
+    synchronized void disconnectDevices() {
         // Disconnect devices handled by BluetoothService.
         for (BluetoothDevice device: getConnectedInputDevices()) {
             disconnectInputDevice(device);
@@ -395,14 +382,11 @@
         }
     }
 
-    private synchronized void finishDisable(boolean saveSetting) {
-        if (mBluetoothState != BluetoothAdapter.STATE_TURNING_OFF) {
-            return;
-        }
-        mEventLoop.stop();
-        tearDownNativeDataNative();
-        disableNative();
-
+    /**
+     * The Bluetooth has been turned off, but hot. Do bonding, profile,
+     * and internal cleanup
+     */
+    synchronized void finishDisable() {
         // mark in progress bondings as cancelled
         for (String address : mBondState.listInState(BluetoothDevice.BOND_BONDING)) {
             mBondState.setBondState(address, BluetoothDevice.BOND_NONE,
@@ -430,12 +414,6 @@
         mAdapterUuids = null;
         mAdapterSdpHandles = null;
 
-        if (saveSetting) {
-            persistBluetoothOnSetting(false);
-        }
-
-        setBluetoothState(BluetoothAdapter.STATE_OFF);
-
         // Log bluetooth off to battery stats.
         long ident = Binder.clearCallingIdentity();
         try {
@@ -451,6 +429,18 @@
         }
     }
 
+    /**
+     * power off Bluetooth
+     */
+    synchronized void shutoffBluetooth() {
+        tearDownNativeDataNative();
+        disableNative();
+        if (mRestart) {
+            mRestart = false;
+            enable();
+        }
+    }
+
     /** Bring up BT and persist BT on in settings */
     public boolean enable() {
         return enable(true);
@@ -471,21 +461,29 @@
         if (mIsAirplaneSensitive && isAirplaneModeOn() && !mIsAirplaneToggleable) {
             return false;
         }
-        if (mBluetoothState != BluetoothAdapter.STATE_OFF) {
+        mBluetoothState.sendMessage(BluetoothAdapterStateMachine.USER_TURN_ON, saveSetting);
+        return true;
+    }
+
+    /**
+     * Turn on Bluetooth Module, Load firmware, and do all the preparation
+     * needed to get the Bluetooth Module ready but keep it not discoverable
+     * and not connectable.
+     */
+    /* package */ synchronized boolean prepareBluetooth() {
+        if (!setupNativeDataNative()) {
             return false;
         }
-        if (mEnableThread != null && mEnableThread.isAlive()) {
-            return false;
-        }
-        setBluetoothState(BluetoothAdapter.STATE_TURNING_ON);
-        mEnableThread = new EnableThread(saveSetting);
-        mEnableThread.start();
+        mIsDiscovering = false;
+
+        switchConnectable(false);
+        updateSdpRecords();
         return true;
     }
 
     /** Forcibly restart Bluetooth if it is on */
     /* package */ synchronized void restart() {
-        if (mBluetoothState != BluetoothAdapter.STATE_ON) {
+        if (getBluetoothStateInternal() != BluetoothAdapter.STATE_ON) {
             return;
         }
         mRestart = true;
@@ -494,30 +492,10 @@
         }
     }
 
-    private synchronized void setBluetoothState(int state) {
-        if (state == mBluetoothState) {
-            return;
-        }
-
-        if (DBG) Log.d(TAG, "Bluetooth state " + mBluetoothState + " -> " + state);
-
-        Intent intent = new Intent(BluetoothAdapter.ACTION_STATE_CHANGED);
-        intent.putExtra(BluetoothAdapter.EXTRA_PREVIOUS_STATE, mBluetoothState);
-        intent.putExtra(BluetoothAdapter.EXTRA_STATE, state);
-        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
-
-        mBluetoothState = state;
-
-        mContext.sendBroadcast(intent, BLUETOOTH_PERM);
-    }
-
     private final Handler mHandler = new Handler() {
         @Override
         public void handleMessage(Message msg) {
             switch (msg.what) {
-            case MESSAGE_FINISH_DISABLE:
-                finishDisable(msg.arg1 != 0);
-                break;
             case MESSAGE_UUID_INTENT:
                 String address = (String)msg.obj;
                 if (address != null) {
@@ -545,65 +523,6 @@
         }
     };
 
-    private EnableThread mEnableThread;
-
-    private class EnableThread extends Thread {
-        private final boolean mSaveSetting;
-        public EnableThread(boolean saveSetting) {
-            mSaveSetting = saveSetting;
-        }
-        public void run() {
-            boolean res = (enableNative() == 0);
-            if (res) {
-                int retryCount = 2;
-                boolean running = false;
-                while ((retryCount-- > 0) && !running) {
-                    mEventLoop.start();
-                    // it may take a moment for the other thread to do its
-                    // thing.  Check periodically for a while.
-                    int pollCount = 5;
-                    while ((pollCount-- > 0) && !running) {
-                        if (mEventLoop.isEventLoopRunning()) {
-                            running = true;
-                            break;
-                        }
-                        try {
-                            Thread.sleep(100);
-                        } catch (InterruptedException e) {}
-                    }
-                }
-                if (!running) {
-                    Log.e(TAG, "bt EnableThread giving up");
-                    res = false;
-                    disableNative();
-                }
-            }
-
-            if (res) {
-                if (!setupNativeDataNative()) {
-                    return;
-                }
-                if (mSaveSetting) {
-                    persistBluetoothOnSetting(true);
-                }
-
-                mIsDiscovering = false;
-                mBondState.readAutoPairingData();
-                mBondState.initBondState();
-                initProfileState();
-
-                // This should be the last step of the the enable thread.
-                // Because this adds SDP records which asynchronously
-                // broadcasts the Bluetooth On State in updateBluetoothState.
-                // So we want all internal state setup before this.
-                updateSdpRecords();
-            } else {
-                setBluetoothState(BluetoothAdapter.STATE_OFF);
-            }
-            mEnableThread = null;
-        }
-    }
-
     private synchronized void addReservedSdpRecords(final ArrayList<ParcelUuid> uuids) {
         //Register SDP records.
         int[] svcIdentifiers = new int[uuids.size()];
@@ -650,38 +569,37 @@
      * for adapter comes in with UUID property.
      * @param uuidsThe uuids of adapter as reported by Bluez.
      */
-    synchronized void updateBluetoothState(String uuids) {
-        if (mBluetoothState == BluetoothAdapter.STATE_TURNING_ON) {
-            ParcelUuid[] adapterUuids = convertStringToParcelUuid(uuids);
+    /*package*/ synchronized void updateBluetoothState(String uuids) {
+        ParcelUuid[] adapterUuids = convertStringToParcelUuid(uuids);
 
-            if (mAdapterUuids != null &&
-                    BluetoothUuid.containsAllUuids(adapterUuids, mAdapterUuids)) {
-                setBluetoothState(BluetoothAdapter.STATE_ON);
-                autoConnect();
-                String[] propVal = {"Pairable", getProperty("Pairable")};
-                mEventLoop.onPropertyChanged(propVal);
-
-                // Log bluetooth on to battery stats.
-                long ident = Binder.clearCallingIdentity();
-                try {
-                    mBatteryStats.noteBluetoothOn();
-                } catch (RemoteException e) {
-                } finally {
-                    Binder.restoreCallingIdentity(ident);
-                }
-
-                if (mIsAirplaneSensitive && isAirplaneModeOn() && !mIsAirplaneToggleable) {
-                    disable(false);
-                }
-            }
+        if (mAdapterUuids != null &&
+            BluetoothUuid.containsAllUuids(adapterUuids, mAdapterUuids)) {
+            mBluetoothState.sendMessage(BluetoothAdapterStateMachine.SERVICE_RECORD_LOADED);
         }
     }
 
-    private void persistBluetoothOnSetting(boolean bluetoothOn) {
-        long origCallerIdentityToken = Binder.clearCallingIdentity();
-        Settings.Secure.putInt(mContext.getContentResolver(), Settings.Secure.BLUETOOTH_ON,
-                bluetoothOn ? 1 : 0);
-        Binder.restoreCallingIdentity(origCallerIdentityToken);
+    /**
+     * This method is called immediately after Bluetooth module is turned on.
+     * It starts auto-connection and places bluetooth on sign onto the battery
+     * stats
+     */
+    /*package*/ void runBluetooth() {
+        mIsDiscovering = false;
+        mBondState.readAutoPairingData();
+        mBondState.initBondState();
+        initProfileState();
+
+        autoConnect();
+
+        // Log bluetooth on to battery stats.
+        long ident = Binder.clearCallingIdentity();
+        try {
+            mBatteryStats.noteBluetoothOn();
+        } catch (RemoteException e) {
+            Log.e(TAG, "", e);
+        } finally {
+            Binder.restoreCallingIdentity(ident);
+        }
     }
 
     /*package*/ synchronized boolean attemptAutoPair(String address) {
@@ -818,6 +736,26 @@
     public synchronized boolean setScanMode(int mode, int duration) {
         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS,
                                                 "Need WRITE_SECURE_SETTINGS permission");
+        return setScanMode(mode, duration, true);
+    }
+
+    /**
+     * @param on true set the local Bluetooth module to be connectable
+     *                but not dicoverable
+     *           false set the local Bluetooth module to be not connectable
+     *                 and not dicoverable
+     */
+    /*package*/ synchronized void switchConnectable(boolean on) {
+        if (on) {
+            // 0 is a dummy value, does not apply for SCAN_MODE_CONNECTABLE
+            setScanMode(BluetoothAdapter.SCAN_MODE_CONNECTABLE, 0, false);
+        } else {
+            // 0 is a dummy value, does not apply for SCAN_MODE_NONE
+            setScanMode(BluetoothAdapter.SCAN_MODE_NONE, 0, false);
+        }
+    }
+
+    private synchronized boolean setScanMode(int mode, int duration, boolean allowOnlyInOnState) {
         boolean pairable;
         boolean discoverable;
 
@@ -839,9 +777,15 @@
             Log.w(TAG, "Requested invalid scan mode " + mode);
             return false;
         }
-        setPropertyBoolean("Pairable", pairable);
-        setPropertyBoolean("Discoverable", discoverable);
 
+        if (allowOnlyInOnState) {
+            setPropertyBoolean("Pairable", pairable);
+            setPropertyBoolean("Discoverable", discoverable);
+        } else {
+            // allowed to set the property through native layer directly
+            setAdapterPropertyBooleanNative("Pairable", pairable ? 1 : 0);
+            setAdapterPropertyBooleanNative("Discoverable", discoverable ? 1 : 0);
+        }
         return true;
     }
 
@@ -1569,14 +1513,10 @@
                 ContentResolver resolver = context.getContentResolver();
                 // Query the airplane mode from Settings.System just to make sure that
                 // some random app is not sending this intent and disabling bluetooth
-                boolean enabled = !isAirplaneModeOn();
-                // If bluetooth is currently expected to be on, then enable or disable bluetooth
-                if (Settings.Secure.getInt(resolver, Settings.Secure.BLUETOOTH_ON, 0) > 0) {
-                    if (enabled) {
-                        enable(false);
-                    } else {
-                        disable(false);
-                    }
+                if (isAirplaneModeOn()) {
+                    mBluetoothState.sendMessage(BluetoothAdapterStateMachine.AIRPLANE_MODE_ON);
+                } else {
+                    mBluetoothState.sendMessage(BluetoothAdapterStateMachine.AIRPLANE_MODE_OFF);
                 }
             } else if (Intent.ACTION_DOCK_EVENT.equals(action)) {
                 int state = intent.getIntExtra(Intent.EXTRA_DOCK_STATE,
@@ -1650,8 +1590,7 @@
 
     @Override
     protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
-        dumpBluetoothState(pw);
-        if (mBluetoothState != BluetoothAdapter.STATE_ON) {
+        if (getBluetoothStateInternal() != BluetoothAdapter.STATE_ON) {
             return;
         }
 
@@ -1840,25 +1779,6 @@
         }
     }
 
-    private void dumpBluetoothState(PrintWriter pw) {
-        switch(mBluetoothState) {
-        case BluetoothAdapter.STATE_OFF:
-            pw.println("Bluetooth OFF\n");
-            break;
-        case BluetoothAdapter.STATE_TURNING_ON:
-            pw.println("Bluetooth TURNING ON\n");
-            break;
-        case BluetoothAdapter.STATE_TURNING_OFF:
-            pw.println("Bluetooth TURNING OFF\n");
-            break;
-        case BluetoothAdapter.STATE_ON:
-            pw.println("Bluetooth ON\n");
-            break;
-        default:
-            pw.println("Bluetooth UNKNOWN STATE " + mBluetoothState);
-        }
-    }
-
     private BluetoothProfile.ServiceListener mBluetoothProfileServiceListener =
         new BluetoothProfile.ServiceListener() {
         public void onServiceConnected(int profile, BluetoothProfile proxy) {
@@ -2389,7 +2309,7 @@
     public synchronized void sendConnectionStateChange(BluetoothDevice device, int state,
                                                         int prevState) {
         // Since this is a binder call check if Bluetooth is on still
-        if (mBluetoothState == BluetoothAdapter.STATE_OFF) return;
+        if (getBluetoothStateInternal() == BluetoothAdapter.STATE_OFF) return;
 
         if (updateCountersAndCheckForConnectionStateChange(state, prevState)) {
             if (!validateProfileConnectionState(state) ||
@@ -2405,6 +2325,10 @@
 
             mAdapterConnectionState = state;
 
+            if (state == BluetoothProfile.STATE_DISCONNECTED) {
+                mBluetoothState.sendMessage(BluetoothAdapterStateMachine.ALL_DEVICES_DISCONNECTED);
+            }
+
             Intent intent = new Intent(BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED);
             intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device);
             intent.putExtra(BluetoothAdapter.EXTRA_CONNECTION_STATE,
@@ -2598,8 +2522,8 @@
     /*package*/ native String getAdapterPathNative();
 
     private native int isEnabledNative();
-    private native int enableNative();
-    private native int disableNative();
+    /*package*/ native int enableNative();
+    /*package*/ native int disableNative();
 
     /*package*/ native Object[] getAdapterPropertiesNative();
     private native Object[] getDevicePropertiesNative(String objectPath);
diff --git a/core/java/android/service/textservice/SpellCheckerService.java b/core/java/android/service/textservice/SpellCheckerService.java
index 6ac99ca..270f512 100644
--- a/core/java/android/service/textservice/SpellCheckerService.java
+++ b/core/java/android/service/textservice/SpellCheckerService.java
@@ -36,7 +36,8 @@
  */
 public abstract class SpellCheckerService extends Service {
     private static final String TAG = SpellCheckerService.class.getSimpleName();
-    public static final String SERVICE_INTERFACE = SpellCheckerService.class.getName();
+    public static final String SERVICE_INTERFACE =
+            "android.service.textservice.SpellCheckerService";
 
     private final SpellCheckerServiceBinder mBinder = new SpellCheckerServiceBinder(this);
 
diff --git a/core/java/android/view/Surface.java b/core/java/android/view/Surface.java
index c913bb3..836867b 100644
--- a/core/java/android/view/Surface.java
+++ b/core/java/android/view/Surface.java
@@ -161,6 +161,9 @@
      */
     public static final int FLAGS_ORIENTATION_ANIMATION_DISABLE = 0x000000001;
 
+    // The mSurfaceControl will only be present for Surfaces used by the window
+    // server or system processes. When this class is parceled we defer to the
+    // mSurfaceControl to do the parceling. Otherwise we parcel the mNativeSurface.
     @SuppressWarnings("unused")
     private int mSurfaceControl;
     @SuppressWarnings("unused")
@@ -202,6 +205,19 @@
     native private static void nativeClassInit();
     static { nativeClassInit(); }
 
+    /**
+     * Create Surface from a SurfaceTexture.
+     *
+     * @param surfaceTexture The {@link SurfaceTexture} that is updated by this Surface.
+     * @hide
+     */
+    public Surface(SurfaceTexture surfaceTexture) {
+        if (DEBUG_RELEASE) {
+            mCreationStack = new Exception();
+        }
+        mCanvas = new CompatibleCanvas();
+        initFromSurfaceTexture(surfaceTexture);
+    }
     
     /**
      * create a surface
@@ -505,5 +521,7 @@
 
     private native void init(Parcel source);
 
+    private native void initFromSurfaceTexture(SurfaceTexture surfaceTexture);
+
     private native int getIdentity();
 }
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index c68b01c..dbb19e4 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -4280,6 +4280,36 @@
     }
 
     /**
+     * Set whether or not this view should account for system screen decorations
+     * such as the status bar and inset its content. This allows this view to be
+     * positioned in absolute screen coordinates and remain visible to the user.
+     *
+     * <p>This should only be used by top-level window decor views.
+     *
+     * @param fitSystemWindows true to inset content for system screen decorations, false for
+     *                         default behavior.
+     *
+     * @attr ref android.R.styleable#View_fitsSystemWindows
+     */
+    public void setFitsSystemWindows(boolean fitSystemWindows) {
+        setFlags(fitSystemWindows ? FITS_SYSTEM_WINDOWS : 0, FITS_SYSTEM_WINDOWS);
+    }
+
+    /**
+     * Check for the FITS_SYSTEM_WINDOWS flag. If this method returns true, this view
+     * will account for system screen decorations such as the status bar and inset its
+     * content. This allows the view to be positioned in absolute screen coordinates
+     * and remain visible to the user.
+     *
+     * @return true if this view will adjust its content bounds for system screen decorations.
+     *
+     * @attr ref android.R.styleable#View_fitsSystemWindows
+     */
+    public boolean fitsSystemWindows() {
+        return (mViewFlags & FITS_SYSTEM_WINDOWS) == FITS_SYSTEM_WINDOWS;
+    }
+
+    /**
      * Returns the visibility status for this view.
      *
      * @return One of {@link #VISIBLE}, {@link #INVISIBLE}, or {@link #GONE}.
diff --git a/core/java/android/view/accessibility/AccessibilityManager.java b/core/java/android/view/accessibility/AccessibilityManager.java
index 83c73cb..a80c2a7 100644
--- a/core/java/android/view/accessibility/AccessibilityManager.java
+++ b/core/java/android/view/accessibility/AccessibilityManager.java
@@ -67,13 +67,17 @@
 
     private static final String LOG_TAG = "AccessibilityManager";
 
+    /** @hide */
+    public static final int STATE_FLAG_ACCESSIBILITY_ENABLED = 0x00000001;
+
+    /** @hide */
+    public static final int STATE_FLAG_TOUCH_EXPLORATION_ENABLED = 0x00000002;
+
     static final Object sInstanceSync = new Object();
 
     private static AccessibilityManager sInstance;
 
-    private static final int DO_SET_ACCESSIBILITY_ENABLED = 10;
-
-    private static final int DO_SET_TOUCH_EXPLORATION_ENABLED = 20;
+    private static final int DO_SET_STATE = 10;
 
     final IAccessibilityManager mService;
 
@@ -100,13 +104,8 @@
     }
 
     final IAccessibilityManagerClient.Stub mClient = new IAccessibilityManagerClient.Stub() {
-        public void setEnabled(boolean enabled) {
-            mHandler.obtainMessage(DO_SET_ACCESSIBILITY_ENABLED, enabled ? 1 : 0, 0).sendToTarget();
-        }
-
-        public void setTouchExplorationEnabled(boolean enabled) {
-            mHandler.obtainMessage(DO_SET_TOUCH_EXPLORATION_ENABLED,
-                    enabled ? 1 : 0, 0).sendToTarget();
+        public void setState(int state) {
+            mHandler.obtainMessage(DO_SET_STATE, state, 0).sendToTarget();
         }
     };
 
@@ -119,14 +118,8 @@
         @Override
         public void handleMessage(Message message) {
             switch (message.what) {
-                case DO_SET_ACCESSIBILITY_ENABLED :
-                    final boolean isAccessibilityEnabled = (message.arg1 == 1);
-                    setAccessibilityState(isAccessibilityEnabled);
-                    return;
-                case DO_SET_TOUCH_EXPLORATION_ENABLED :
-                    synchronized (mHandler) {
-                        mIsTouchExplorationEnabled = (message.arg1 == 1);
-                    }
+                case DO_SET_STATE :
+                    setState(message.arg1);
                     return;
                 default :
                     Log.w(LOG_TAG, "Unknown message type: " + message.what);
@@ -163,8 +156,8 @@
         mService = service;
 
         try {
-            final boolean isEnabled = mService.addClient(mClient);
-            setAccessibilityState(isEnabled);
+            final int stateFlags = mService.addClient(mClient);
+            setState(stateFlags);
         } catch (RemoteException re) {
             Log.e(LOG_TAG, "AccessibilityManagerService is dead", re);
         }
@@ -341,6 +334,17 @@
     }
 
     /**
+     * Sets the current state.
+     *
+     * @param stateFlags The state flags.
+     */
+    private void setState(int stateFlags) {
+        final boolean accessibilityEnabled = (stateFlags & STATE_FLAG_ACCESSIBILITY_ENABLED) != 0;
+        setAccessibilityState(accessibilityEnabled);
+        mIsTouchExplorationEnabled = (stateFlags & STATE_FLAG_TOUCH_EXPLORATION_ENABLED) != 0;
+    }
+
+    /**
      * Sets the enabled state.
      *
      * @param isEnabled The accessibility state.
diff --git a/core/java/android/view/accessibility/AccessibilityNodeInfo.java b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
index 0e04471..6469b35 100644
--- a/core/java/android/view/accessibility/AccessibilityNodeInfo.java
+++ b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
@@ -294,14 +294,14 @@
     }
 
     /**
-     * Gets the unique id identifying this node's parent.
+     * Gets the parent.
      * <p>
      *   <strong>Note:</strong> It is a client responsibility to recycle the
      *     received info by calling {@link AccessibilityNodeInfo#recycle()}
      *     to avoid creating of multiple instances.
      * </p>
      *
-     * @return The node's patent id.
+     * @return The parent.
      */
     public AccessibilityNodeInfo getParent() {
         enforceSealed();
diff --git a/core/java/android/view/accessibility/IAccessibilityManager.aidl b/core/java/android/view/accessibility/IAccessibilityManager.aidl
index b14f02a..c621ff6 100644
--- a/core/java/android/view/accessibility/IAccessibilityManager.aidl
+++ b/core/java/android/view/accessibility/IAccessibilityManager.aidl
@@ -34,7 +34,7 @@
  */
 interface IAccessibilityManager {
 
-    boolean addClient(IAccessibilityManagerClient client);
+    int addClient(IAccessibilityManagerClient client);
 
     boolean sendAccessibilityEvent(in AccessibilityEvent uiEvent);
 
diff --git a/core/java/android/view/accessibility/IAccessibilityManagerClient.aidl b/core/java/android/view/accessibility/IAccessibilityManagerClient.aidl
index 4e69692..5e7e813 100644
--- a/core/java/android/view/accessibility/IAccessibilityManagerClient.aidl
+++ b/core/java/android/view/accessibility/IAccessibilityManagerClient.aidl
@@ -24,7 +24,5 @@
  */
 oneway interface IAccessibilityManagerClient {
 
-    void setEnabled(boolean enabled);
-
-    void setTouchExplorationEnabled(boolean enabled);
+    void setState(int stateFlags);
 }
diff --git a/core/java/android/view/textservice/SpellCheckerInfo.java b/core/java/android/view/textservice/SpellCheckerInfo.java
index 1205adf..d88a39f 100644
--- a/core/java/android/view/textservice/SpellCheckerInfo.java
+++ b/core/java/android/view/textservice/SpellCheckerInfo.java
@@ -18,8 +18,10 @@
 
 import android.content.ComponentName;
 import android.content.Context;
+import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
 import android.content.pm.ServiceInfo;
+import android.graphics.drawable.Drawable;
 import android.os.Parcel;
 import android.os.Parcelable;
 
@@ -103,6 +105,24 @@
     };
 
     /**
+     * Load the user-displayed label for this spell checker.
+     *
+     * @param pm Supply a PackageManager used to load the spell checker's resources.
+     */
+    public CharSequence loadLabel(PackageManager pm) {
+        return mService.loadLabel(pm);
+    }
+
+    /**
+     * Load the user-displayed icon for this spell checker.
+     *
+     * @param pm Supply a PackageManager used to load the spell checker's resources.
+     */
+    public Drawable loadIcon(PackageManager pm) {
+        return mService.loadIcon(pm);
+    }
+
+    /**
      * Used to make this class parcelable.
      */
     @Override
diff --git a/core/java/android/view/textservice/TextServicesManager.java b/core/java/android/view/textservice/TextServicesManager.java
index 9749416..229b414 100644
--- a/core/java/android/view/textservice/TextServicesManager.java
+++ b/core/java/android/view/textservice/TextServicesManager.java
@@ -97,4 +97,27 @@
         }
         return session;
     }
+
+    /**
+     * @hide
+     */
+    public SpellCheckerInfo[] getEnabledSpellCheckers() {
+        try {
+            return sService.getEnabledSpellCheckers();
+        } catch (RemoteException e) {
+            return null;
+        }
+    }
+
+    /**
+     * @hide
+     */
+    public SpellCheckerInfo getCurrentSpellChecker() {
+        try {
+            // Passing null as a locale for ICS
+            return sService.getCurrentSpellChecker(null);
+        } catch (RemoteException e) {
+            return null;
+        }
+    }
 }
diff --git a/core/java/android/webkit/JniUtil.java b/core/java/android/webkit/JniUtil.java
index bb4d192..620973e 100644
--- a/core/java/android/webkit/JniUtil.java
+++ b/core/java/android/webkit/JniUtil.java
@@ -18,6 +18,7 @@
 
 import android.content.Context;
 import android.net.Uri;
+import android.provider.Settings;
 import android.util.Log;
 
 import java.io.InputStream;
@@ -38,7 +39,7 @@
 
     private static boolean initialized = false;
 
-    private static void checkIntialized() {
+    private static void checkInitialized() {
         if (!initialized) {
             throw new IllegalStateException("Call CookieSyncManager::createInstance() or create a webview before using this class");
         }
@@ -63,7 +64,7 @@
      * @return String The application's database directory
      */
     private static synchronized String getDatabaseDirectory() {
-        checkIntialized();
+        checkInitialized();
 
         if (sDatabaseDirectory == null)
             sDatabaseDirectory = sContext.getDatabasePath("dummy").getParent();
@@ -76,7 +77,7 @@
      * @return String The application's cache directory
      */
     private static synchronized String getCacheDirectory() {
-        checkIntialized();
+        checkInitialized();
 
         if (sCacheDirectory == null)
             sCacheDirectory = sContext.getCacheDir().getAbsolutePath();
@@ -166,5 +167,13 @@
         return sUseChromiumHttpStack;
     }
 
+    private static synchronized String getAutofillQueryUrl() {
+        checkInitialized();
+        // If the device has not checked in it won't have pulled down the system setting for the
+        // Autofill Url. In that case we will not make autofill server requests.
+        return Settings.Secure.getString(sContext.getContentResolver(),
+                Settings.Secure.WEB_AUTOFILL_QUERY_URL);
+    }
+
     private static native boolean nativeUseChromiumHttpStack();
 }
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 6a3b2ff..e24ab58 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -4701,6 +4701,7 @@
         private Message mUpdateMessage;
         private boolean mAutoFillable;
         private boolean mAutoComplete;
+        private WebSettings mWebSettings;
 
         public RequestFormData(String name, String url, Message msg,
                 boolean autoFillable, boolean autoComplete) {
@@ -4709,6 +4710,7 @@
             mUpdateMessage = msg;
             mAutoFillable = autoFillable;
             mAutoComplete = autoComplete;
+            mWebSettings = getSettings();
         }
 
         public void run() {
@@ -4718,8 +4720,7 @@
                 // Note that code inside the adapter click handler in WebTextView depends
                 // on the AutoFill item being at the top of the drop down list. If you change
                 // the order, make sure to do it there too!
-                WebSettings settings = getSettings();
-                if (settings != null && settings.getAutoFillProfile() != null) {
+                if (mWebSettings != null && mWebSettings.getAutoFillProfile() != null) {
                     pastEntries.add(getResources().getText(
                             com.android.internal.R.string.autofill_this_form).toString() +
                             " " +
diff --git a/core/java/android/widget/PopupWindow.java b/core/java/android/widget/PopupWindow.java
index 563fc26..36927ca 100644
--- a/core/java/android/widget/PopupWindow.java
+++ b/core/java/android/widget/PopupWindow.java
@@ -91,6 +91,7 @@
     private boolean mLayoutInScreen;
     private boolean mClipToScreen;
     private boolean mAllowScrollingAnchorParent = true;
+    private boolean mLayoutInsetDecor = false;
 
     private OnTouchListener mTouchInterceptor;
     
@@ -658,6 +659,22 @@
     }
 
     /**
+     * Allows the popup window to force the flag
+     * {@link WindowManager.LayoutParams#FLAG_LAYOUT_INSET_DECOR}, overriding default behavior.
+     * This will cause the popup to inset its content to account for system windows overlaying
+     * the screen, such as the status bar.
+     *
+     * <p>This will often be combined with {@link #setLayoutInScreenEnabled(boolean)}.
+     *
+     * @param enabled true if the popup's views should inset content to account for system windows,
+     *                the way that decor views behave for full-screen windows.
+     * @hide
+     */
+    public void setLayoutInsetDecor(boolean enabled) {
+        mLayoutInsetDecor = enabled;
+    }
+
+    /**
      * Set the layout type for this window. Should be one of the TYPE constants defined in
      * {@link WindowManager.LayoutParams}.
      *
@@ -942,6 +959,7 @@
         if (mContext != null) {
             p.packageName = mContext.getPackageName();
         }
+        mPopupView.setFitsSystemWindows(mLayoutInsetDecor);
         mWindowManager.addView(mPopupView, p);
     }
 
@@ -1012,6 +1030,9 @@
         if (mLayoutInScreen) {
             curFlags |= WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
         }
+        if (mLayoutInsetDecor) {
+            curFlags |= WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR;
+        }
         return curFlags;
     }
     
diff --git a/core/java/android/widget/SearchView.java b/core/java/android/widget/SearchView.java
index b2d1a1e..55b73df 100644
--- a/core/java/android/widget/SearchView.java
+++ b/core/java/android/widget/SearchView.java
@@ -45,6 +45,7 @@
 import android.util.AttributeSet;
 import android.util.Log;
 import android.util.TypedValue;
+import android.view.CollapsibleActionView;
 import android.view.KeyEvent;
 import android.view.LayoutInflater;
 import android.view.View;
@@ -58,18 +59,30 @@
 import java.util.WeakHashMap;
 
 /**
- * A widget that provides a user interface for the user to enter a search query and submit a
- * request to a search provider. Shows a list of query suggestions or results, if
- * available, and allows the user to pick a suggestion or result to launch into.
+ * A widget that provides a user interface for the user to enter a search query and submit a request
+ * to a search provider. Shows a list of query suggestions or results, if available, and allows the
+ * user to pick a suggestion or result to launch into.
  *
- * <p>For more information, see the <a href="{@docRoot}guide/topics/search/index.html">Search</a>
- * documentation.<p>
+ * <p>
+ * When the SearchView is used in an ActionBar as an action view for a collapsible menu item, it
+ * needs to be set to iconified by default using {@link #setIconifiedByDefault(boolean)
+ * setIconifiedByDefault(true)}. This is the default, so nothing needs to be done.
+ * </p>
+ * <p>
+ * If you want the search field to always be visible, then call setIconifiedByDefault(false).
+ * </p>
  *
+ * <p>
+ * For more information, see the <a href="{@docRoot}guide/topics/search/index.html">Search</a>
+ * documentation.
+ * <p>
+ *
+ * @see android.view.MenuItem#SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW
  * @attr ref android.R.styleable#SearchView_iconifiedByDefault
  * @attr ref android.R.styleable#SearchView_maxWidth
  * @attr ref android.R.styleable#SearchView_queryHint
  */
-public class SearchView extends LinearLayout {
+public class SearchView extends LinearLayout implements CollapsibleActionView {
 
     private static final boolean DBG = false;
     private static final String LOG_TAG = "SearchView";
@@ -100,6 +113,7 @@
     private int mMaxWidth;
     private boolean mVoiceButtonEnabled;
     private CharSequence mUserQuery;
+    private boolean mExpandedInActionView;
 
     private SearchableInfo mSearchable;
     private Bundle mAppSearchData;
@@ -623,7 +637,7 @@
         final boolean hasText = !TextUtils.isEmpty(mQueryTextView.getText());
         // Should we show the close button? It is not shown if there's no focus,
         // field is not iconified by default and there is no text in it.
-        final boolean showClose = hasText || mIconifiedByDefault;
+        final boolean showClose = hasText || (mIconifiedByDefault && !mExpandedInActionView);
         mCloseButton.setVisibility(showClose ? VISIBLE : INVISIBLE);
         mCloseButton.getDrawable().setState(hasText ? ENABLED_STATE_SET : EMPTY_STATE_SET);
     }
@@ -1022,6 +1036,25 @@
         super.onAttachedToWindow();
     }
 
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void onActionViewCollapsed() {
+        mQueryTextView.setText("");
+        setIconified(true);
+        mExpandedInActionView = false;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void onActionViewExpanded() {
+        mExpandedInActionView = true;
+        setIconified(false);
+    }
+
     private void adjustDropDownSizeAndPosition() {
         if (mDropDownAnchor.getWidth() > 1) {
             Resources res = getContext().getResources();
diff --git a/core/java/android/widget/Switch.java b/core/java/android/widget/Switch.java
index b7565f3..0c80a11 100644
--- a/core/java/android/widget/Switch.java
+++ b/core/java/android/widget/Switch.java
@@ -34,6 +34,7 @@
 import android.view.MotionEvent;
 import android.view.VelocityTracker;
 import android.view.ViewConfiguration;
+import android.view.accessibility.AccessibilityEvent;
 
 import com.android.internal.R;
 
@@ -360,6 +361,13 @@
         }
     }
 
+    @Override
+    public void onPopulateAccessibilityEvent(AccessibilityEvent event) {
+        super.onPopulateAccessibilityEvent(event);
+        Layout switchText = getTargetCheckedState() ? mOnLayout : mOffLayout;
+        event.getText().add(switchText.getText());
+    }
+
     private Layout makeLayout(CharSequence text) {
         return new StaticLayout(text, mTextPaint,
                 (int) Math.ceil(Layout.getDesiredWidth(text, mTextPaint)),
diff --git a/core/java/com/android/internal/textservice/ITextServicesManager.aidl b/core/java/com/android/internal/textservice/ITextServicesManager.aidl
index ad0c1ff..2a045e3 100644
--- a/core/java/com/android/internal/textservice/ITextServicesManager.aidl
+++ b/core/java/com/android/internal/textservice/ITextServicesManager.aidl
@@ -32,4 +32,5 @@
             in ITextServicesSessionListener tsListener,
             in ISpellCheckerSessionListener scListener);
     oneway void finishSpellCheckerService(in ISpellCheckerSessionListener listener);
+    SpellCheckerInfo[] getEnabledSpellCheckers();
 }
diff --git a/core/jni/android_view_Surface.cpp b/core/jni/android_view_Surface.cpp
index 0dc9293..4c1ca31 100644
--- a/core/jni/android_view_Surface.cpp
+++ b/core/jni/android_view_Surface.cpp
@@ -22,6 +22,7 @@
 #include "android/graphics/GraphicsJNI.h"
 
 #include <binder/IMemory.h>
+#include <gui/SurfaceTexture.h>
 #include <surfaceflinger/SurfaceComposerClient.h>
 #include <surfaceflinger/Surface.h>
 #include <ui/Region.h>
@@ -38,6 +39,7 @@
 #include "JNIHelp.h"
 #include <android_runtime/AndroidRuntime.h>
 #include <android_runtime/android_view_Surface.h>
+#include <android_runtime/android_graphics_SurfaceTexture.h>
 #include <utils/misc.h>
 
 
@@ -244,6 +246,19 @@
     setSurfaceControl(env, clazz, surface);
 }
 
+static void Surface_initFromSurfaceTexture(
+        JNIEnv* env, jobject clazz, jobject jst)
+{
+    sp<ISurfaceTexture> st(SurfaceTexture_getSurfaceTexture(env, jst));
+    sp<Surface> surface(new Surface(st));
+    if (surface == NULL) {
+        jniThrowException(env, OutOfResourcesException, NULL);
+        return;
+    }
+    setSurfaceControl(env, clazz, NULL);
+    setSurface(env, clazz, surface);
+}
+
 static void Surface_initParcel(JNIEnv* env, jobject clazz, jobject argParcel)
 {
     Parcel* parcel = (Parcel*)env->GetIntField(argParcel, no.native_parcel);
@@ -761,10 +776,26 @@
         return;
     }
 
+    // The Java instance may have a SurfaceControl (in the case of the
+    // WindowManager or a system app). In that case, we defer to the
+    // SurfaceControl to send its ISurface. Otherwise, if the Surface is
+    // available we let it parcel itself. Finally, if the Surface is also
+    // NULL we fall back to using the SurfaceControl path which sends an
+    // empty surface; this matches legacy behavior.
     const sp<SurfaceControl>& control(getSurfaceControl(env, clazz));
-    SurfaceControl::writeSurfaceToParcel(control, parcel);
+    if (control != NULL) {
+        SurfaceControl::writeSurfaceToParcel(control, parcel);
+    } else {
+        sp<Surface> surface(Surface_getSurface(env, clazz));
+        if (surface != NULL) {
+            Surface::writeToParcel(surface, parcel);
+        } else {
+            SurfaceControl::writeSurfaceToParcel(NULL, parcel);
+        }
+    }
     if (flags & PARCELABLE_WRITE_RETURN_VALUE) {
-        setSurfaceControl(env, clazz, 0);
+        setSurfaceControl(env, clazz, NULL);
+        setSurface(env, clazz, NULL);
     }
 }
 
@@ -784,6 +815,7 @@
     {"nativeClassInit",     "()V",  (void*)nativeClassInit },
     {"init",                "(Landroid/view/SurfaceSession;ILjava/lang/String;IIIII)V",  (void*)Surface_init },
     {"init",                "(Landroid/os/Parcel;)V",  (void*)Surface_initParcel },
+    {"initFromSurfaceTexture", "(Landroid/graphics/SurfaceTexture;)V", (void*)Surface_initFromSurfaceTexture },
     {"getIdentity",         "()I",  (void*)Surface_getIdentity },
     {"destroy",             "()V",  (void*)Surface_destroy },
     {"release",             "()V",  (void*)Surface_release },
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 7d7aea9..b5fc55e 100755
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -2278,6 +2278,8 @@
             <flag name="feedbackVisual" value="0x00000008" />
             <!-- Provides {@link android.accessibilityservice.AccessibilityServiceInfo#FEEDBACK_GENERIC} feedback. -->
             <flag name="feedbackGeneric" value="0x00000010" />
+            <!-- Provides {@link android.accessibilityservice.AccessibilityServiceInfo#FEEDBACK_ALL_MASK} feedback. -->
+            <flag name="feedbackAllMask" value="0xffffffff" />
         </attr>
         <!-- The minimal period in milliseconds between two accessibility events of the same type
              are sent to this serivce. This setting can be changed at runtime by calling
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 2b2f356..65dce49 100755
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -469,6 +469,10 @@
          speech -->
     <bool name="config_bluetooth_wide_band_speech">true</bool>
 
+    <!-- Boolean indicating if current platform supports quick switch-on/off of
+         Bluetooth Module -->
+    <bool name="config_bluetooth_adapter_quick_switch">true</bool>
+
     <!-- The default data-use polling period. -->
     <integer name="config_datause_polling_period_sec">600</integer>
 
diff --git a/core/tests/coretests/src/android/view/accessibility/RecycleAccessibilityEventTest.java b/core/tests/coretests/src/android/view/accessibility/RecycleAccessibilityEventTest.java
index bbf1696..4814c61 100644
--- a/core/tests/coretests/src/android/view/accessibility/RecycleAccessibilityEventTest.java
+++ b/core/tests/coretests/src/android/view/accessibility/RecycleAccessibilityEventTest.java
@@ -65,13 +65,13 @@
         assertEquals(0, first.getText().size());
         assertFalse(first.isChecked());
         assertNull(first.getContentDescription());
-        assertEquals(0, first.getItemCount());
+        assertEquals(-1, first.getItemCount());
         assertEquals(AccessibilityEvent.INVALID_POSITION, first.getCurrentItemIndex());
         assertFalse(first.isEnabled());
         assertFalse(first.isPassword());
-        assertEquals(0, first.getFromIndex());
-        assertEquals(0, first.getAddedCount());
-        assertEquals(0, first.getRemovedCount());
+        assertEquals(-1, first.getFromIndex());
+        assertEquals(-1, first.getAddedCount());
+        assertEquals(-1, first.getRemovedCount());
 
         // get another event from the pool (this must be the recycled first)
         AccessibilityEvent second = AccessibilityEvent.obtain();
diff --git a/include/gui/SurfaceTexture.h b/include/gui/SurfaceTexture.h
index 134c208..2a8e725 100644
--- a/include/gui/SurfaceTexture.h
+++ b/include/gui/SurfaceTexture.h
@@ -211,7 +211,6 @@
     // all slots.
     void freeAllBuffers();
     static bool isExternalFormat(uint32_t format);
-    static GLenum getTextureTarget(uint32_t format);
 
 private:
 
@@ -348,10 +347,6 @@
     // reset mCurrentTexture to INVALID_BUFFER_SLOT.
     int mCurrentTexture;
 
-    // mCurrentTextureTarget is the GLES texture target to be used with the
-    // current texture.
-    GLenum mCurrentTextureTarget;
-
     // mCurrentTextureBuf is the graphic buffer of the current texture. It's
     // possible that this buffer is not associated with any buffer slot, so we
     // must track it separately in order to support the getCurrentBuffer method.
diff --git a/include/surfaceflinger/Surface.h b/include/surfaceflinger/Surface.h
index 9c352ad..0460bbd 100644
--- a/include/surfaceflinger/Surface.h
+++ b/include/surfaceflinger/Surface.h
@@ -122,7 +122,10 @@
         uint32_t    reserved[2];
     };
 
+    explicit Surface(const sp<ISurfaceTexture>& st);
+
     static status_t writeToParcel(const sp<Surface>& control, Parcel* parcel);
+
     static sp<Surface> readFromParcel(const Parcel& data);
     static bool isValid(const sp<Surface>& surface) {
         return (surface != 0) && surface->isValid();
@@ -147,14 +150,14 @@
     Surface& operator = (Surface& rhs);
     Surface(const Surface& rhs);
 
-    Surface(const sp<SurfaceControl>& control);
+    explicit Surface(const sp<SurfaceControl>& control);
     Surface(const Parcel& data, const sp<IBinder>& ref);
     ~Surface();
 
     /*
      *  private stuff...
      */
-    void init();
+    void init(const sp<ISurfaceTexture>& surfaceTexture);
 
     static void cleanCachedSurfacesLocked();
 
diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp
index c4f9e53..ccf98e5 100644
--- a/libs/gui/Surface.cpp
+++ b/libs/gui/Surface.cpp
@@ -184,6 +184,7 @@
         identity = control->mIdentity;
     }
     parcel->writeStrongBinder(sur!=0 ? sur->asBinder() : NULL);
+    parcel->writeStrongBinder(NULL);  // NULL ISurfaceTexture in this case.
     parcel->writeInt32(identity);
     return NO_ERROR;
 }
@@ -192,7 +193,8 @@
 {
     Mutex::Autolock _l(mLock);
     if (mSurfaceData == 0) {
-        mSurfaceData = new Surface(const_cast<SurfaceControl*>(this));
+        sp<SurfaceControl> surface_control(const_cast<SurfaceControl*>(this));
+        mSurfaceData = new Surface(surface_control);
     }
     return mSurfaceData;
 }
@@ -208,31 +210,58 @@
       mSurface(surface->mSurface),
       mIdentity(surface->mIdentity)
 {
-    init();
+    sp<ISurfaceTexture> st;
+    if (mSurface != NULL) {
+        st = mSurface->getSurfaceTexture();
+    }
+    init(st);
 }
 
 Surface::Surface(const Parcel& parcel, const sp<IBinder>& ref)
     : SurfaceTextureClient()
 {
-    mSurface    = interface_cast<ISurface>(ref);
+    mSurface = interface_cast<ISurface>(ref);
+    sp<IBinder> st_binder(parcel.readStrongBinder());
+    sp<ISurfaceTexture> st;
+    if (st_binder != NULL) {
+        st = interface_cast<ISurfaceTexture>(st_binder);
+    } else if (mSurface != NULL) {
+        st = mSurface->getSurfaceTexture();
+    }
+
     mIdentity   = parcel.readInt32();
-    init();
+    init(st);
+}
+
+Surface::Surface(const sp<ISurfaceTexture>& st)
+    : SurfaceTextureClient(),
+      mSurface(NULL),
+      mIdentity(0)
+{
+    init(st);
 }
 
 status_t Surface::writeToParcel(
         const sp<Surface>& surface, Parcel* parcel)
 {
     sp<ISurface> sur;
+    sp<ISurfaceTexture> st;
     uint32_t identity = 0;
     if (Surface::isValid(surface)) {
         sur      = surface->mSurface;
+        st       = surface->getISurfaceTexture();
         identity = surface->mIdentity;
-    } else if (surface != 0 && surface->mSurface != 0) {
-        LOGW("Parceling invalid surface with non-NULL ISurface as NULL: "
-             "mSurface = %p, mIdentity = %d",
-             surface->mSurface.get(), surface->mIdentity);
+    } else if (surface != 0 &&
+            (surface->mSurface != NULL ||
+             surface->getISurfaceTexture() != NULL)) {
+        LOGE("Parceling invalid surface with non-NULL ISurface/ISurfaceTexture as NULL: "
+             "mSurface = %p, surfaceTexture = %p, mIdentity = %d, ",
+             surface->mSurface.get(), surface->getISurfaceTexture().get(),
+             surface->mIdentity);
     }
-    parcel->writeStrongBinder(sur!=0 ? sur->asBinder() : NULL);
+
+    parcel->writeStrongBinder(sur != NULL ? sur->asBinder() : NULL);
+    parcel->writeStrongBinder(st != NULL ? st->asBinder() : NULL);
     parcel->writeInt32(identity);
     return NO_ERROR;
 
@@ -249,8 +278,8 @@
        surface = new Surface(data, binder);
        sCachedSurfaces.add(binder, surface);
     }
-    if (surface->mSurface == 0) {
-      surface = 0;
+    if (surface->mSurface == NULL && surface->getISurfaceTexture() == NULL) {
+        surface = 0;
     }
     cleanCachedSurfacesLocked();
     return surface;
@@ -267,10 +296,9 @@
     }
 }
 
-void Surface::init()
+void Surface::init(const sp<ISurfaceTexture>& surfaceTexture)
 {
-    if (mSurface != NULL) {
-        sp<ISurfaceTexture> surfaceTexture(mSurface->getSurfaceTexture());
+    if (mSurface != NULL || surfaceTexture != NULL) {
         LOGE_IF(surfaceTexture==0, "got a NULL ISurfaceTexture from ISurface");
         if (surfaceTexture != NULL) {
             setISurfaceTexture(surfaceTexture);
diff --git a/libs/gui/SurfaceTexture.cpp b/libs/gui/SurfaceTexture.cpp
index c190195..8d19957 100644
--- a/libs/gui/SurfaceTexture.cpp
+++ b/libs/gui/SurfaceTexture.cpp
@@ -86,7 +86,6 @@
     mClientBufferCount(0),
     mServerBufferCount(MIN_ASYNC_BUFFER_SLOTS),
     mCurrentTexture(INVALID_BUFFER_SLOT),
-    mCurrentTextureTarget(GL_TEXTURE_EXTERNAL_OES),
     mCurrentTransform(0),
     mCurrentTimestamp(0),
     mNextTransform(0),
@@ -651,12 +650,8 @@
             LOGW("updateTexImage: clearing GL error: %#04x", error);
         }
 
-        GLenum target = getTextureTarget(mSlots[buf].mGraphicBuffer->format);
-        if (target != mCurrentTextureTarget) {
-            glDeleteTextures(1, &mTexName);
-        }
-        glBindTexture(target, mTexName);
-        glEGLImageTargetTexture2DOES(target, (GLeglImageOES)image);
+        glBindTexture(GL_TEXTURE_EXTERNAL_OES, mTexName);
+        glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, (GLeglImageOES)image);
 
         bool failed = false;
         while ((error = glGetError()) != GL_NO_ERROR) {
@@ -678,7 +673,6 @@
 
         // Update the SurfaceTexture state.
         mCurrentTexture = buf;
-        mCurrentTextureTarget = target;
         mCurrentTextureBuf = mSlots[buf].mGraphicBuffer;
         mCurrentCrop = mSlots[buf].mCrop;
         mCurrentTransform = mSlots[buf].mTransform;
@@ -692,7 +686,7 @@
         mDequeueCondition.signal();
     } else {
         // We always bind the texture even if we don't update its contents.
-        glBindTexture(mCurrentTextureTarget, mTexName);
+        glBindTexture(GL_TEXTURE_EXTERNAL_OES, mTexName);
     }
 
     return OK;
@@ -717,20 +711,8 @@
     return false;
 }
 
-GLenum SurfaceTexture::getTextureTarget(uint32_t format)
-{
-    GLenum target = GL_TEXTURE_2D;
-#if defined(GL_OES_EGL_image_external)
-    if (isExternalFormat(format)) {
-        target = GL_TEXTURE_EXTERNAL_OES;
-    }
-#endif
-    return target;
-}
-
 GLenum SurfaceTexture::getCurrentTextureTarget() const {
-    Mutex::Autolock lock(mMutex);
-    return mCurrentTextureTarget;
+    return GL_TEXTURE_EXTERNAL_OES;
 }
 
 void SurfaceTexture::getTransformMatrix(float mtx[16]) {
@@ -959,12 +941,12 @@
     }
 
     snprintf(buffer, SIZE,
-            "%scurrent: {crop=[%d,%d,%d,%d], transform=0x%02x, current=%d, target=0x%04x}\n"
+            "%scurrent: {crop=[%d,%d,%d,%d], transform=0x%02x, current=%d}\n"
             "%snext   : {crop=[%d,%d,%d,%d], transform=0x%02x, FIFO(%d)={%s}}\n"
             ,
             prefix, mCurrentCrop.left,
             mCurrentCrop.top, mCurrentCrop.right, mCurrentCrop.bottom,
-            mCurrentTransform, mCurrentTexture, mCurrentTextureTarget,
+            mCurrentTransform, mCurrentTexture,
             prefix, mNextCrop.left, mNextCrop.top, mNextCrop.right, mNextCrop.bottom,
             mCurrentTransform, fifoSize, fifo.string()
     );
diff --git a/libs/gui/tests/SurfaceTexture_test.cpp b/libs/gui/tests/SurfaceTexture_test.cpp
index 0fac6cd..44babcf 100644
--- a/libs/gui/tests/SurfaceTexture_test.cpp
+++ b/libs/gui/tests/SurfaceTexture_test.cpp
@@ -832,9 +832,7 @@
     pt->requestExitAndWait();
 }
 
-// XXX: This test is disabled because there are currently no drivers that can
-// handle RGBA textures with the GL_TEXTURE_EXTERNAL_OES target.
-TEST_F(SurfaceTextureGLTest, DISABLED_TexturingFromCpuFilledRGBABufferNpot) {
+TEST_F(SurfaceTextureGLTest, TexturingFromCpuFilledRGBABufferNpot) {
     const int texWidth = 64;
     const int texHeight = 66;
 
@@ -871,26 +869,24 @@
     EXPECT_TRUE(checkPixel( 0, 65,  35,  35,  35,  35));
 
     EXPECT_TRUE(checkPixel(15, 10,  35, 231, 231, 231));
-    EXPECT_TRUE(checkPixel(24, 63,  38, 228, 231,  35));
+    EXPECT_TRUE(checkPixel(23, 65, 231,  35, 231,  35));
     EXPECT_TRUE(checkPixel(19, 40,  35, 231,  35,  35));
     EXPECT_TRUE(checkPixel(38, 30, 231,  35,  35,  35));
     EXPECT_TRUE(checkPixel(42, 54,  35,  35,  35, 231));
-    EXPECT_TRUE(checkPixel(37, 33, 228,  38,  38,  38));
+    EXPECT_TRUE(checkPixel(37, 34,  35, 231, 231, 231));
     EXPECT_TRUE(checkPixel(31,  8, 231,  35,  35, 231));
-    EXPECT_TRUE(checkPixel(36, 47, 228,  35, 231, 231));
-    EXPECT_TRUE(checkPixel(24, 63,  38, 228, 231,  35));
-    EXPECT_TRUE(checkPixel(48,  3, 228, 228,  38,  35));
+    EXPECT_TRUE(checkPixel(37, 47, 231,  35, 231, 231));
+    EXPECT_TRUE(checkPixel(25, 38,  35,  35,  35,  35));
+    EXPECT_TRUE(checkPixel(49,  6,  35, 231,  35,  35));
     EXPECT_TRUE(checkPixel(54, 50,  35, 231, 231, 231));
-    EXPECT_TRUE(checkPixel(24, 25,  41,  41, 231, 231));
-    EXPECT_TRUE(checkPixel(10,  9,  38,  38, 231, 231));
+    EXPECT_TRUE(checkPixel(27, 26, 231, 231, 231, 231));
+    EXPECT_TRUE(checkPixel(10,  6,  35,  35, 231, 231));
     EXPECT_TRUE(checkPixel(29,  4,  35,  35,  35, 231));
-    EXPECT_TRUE(checkPixel(56, 31,  38, 228, 231,  35));
+    EXPECT_TRUE(checkPixel(55, 28,  35,  35, 231,  35));
     EXPECT_TRUE(checkPixel(58, 55,  35,  35, 231, 231));
 }
 
-// XXX: This test is disabled because there are currently no drivers that can
-// handle RGBA textures with the GL_TEXTURE_EXTERNAL_OES target.
-TEST_F(SurfaceTextureGLTest, DISABLED_TexturingFromCpuFilledRGBABufferPow2) {
+TEST_F(SurfaceTextureGLTest, TexturingFromCpuFilledRGBABufferPow2) {
     const int texWidth = 64;
     const int texHeight = 64;
 
@@ -944,9 +940,7 @@
     EXPECT_TRUE(checkPixel( 3, 52,  35, 231,  35,  35));
 }
 
-// XXX: This test is disabled because there are currently no drivers that can
-// handle RGBA textures with the GL_TEXTURE_EXTERNAL_OES target.
-TEST_F(SurfaceTextureGLTest, DISABLED_TexturingFromGLFilledRGBABufferPow2) {
+TEST_F(SurfaceTextureGLTest, TexturingFromGLFilledRGBABufferPow2) {
     const int texWidth = 64;
     const int texHeight = 64;
 
@@ -956,7 +950,7 @@
     EGLSurface stcEglSurface = eglCreateWindowSurface(mEglDisplay, mGlConfig,
             mANW.get(), NULL);
     ASSERT_EQ(EGL_SUCCESS, eglGetError());
-    ASSERT_NE(EGL_NO_SURFACE, mEglSurface);
+    ASSERT_NE(EGL_NO_SURFACE, stcEglSurface);
 
     EXPECT_TRUE(eglMakeCurrent(mEglDisplay, stcEglSurface, stcEglSurface,
             mEglContext));
@@ -980,6 +974,8 @@
 
     eglSwapBuffers(mEglDisplay, stcEglSurface);
 
+    eglDestroySurface(mEglDisplay, stcEglSurface);
+
     // Do the consumer side of things
     EXPECT_TRUE(eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface,
             mEglContext));
diff --git a/media/java/android/media/AudioFormat.java b/media/java/android/media/AudioFormat.java
index 31e4631..82e8d77 100644
--- a/media/java/android/media/AudioFormat.java
+++ b/media/java/android/media/AudioFormat.java
@@ -54,7 +54,8 @@
     /** Default audio channel mask */
     public static final int CHANNEL_OUT_DEFAULT = 1;
 
-    // Channel mask definitions must be kept in sync with native values in include/media/AudioSystem.h
+    // Channel mask definitions must be kept in sync with native values
+    //  in /system/core/include/system/audio.h
     public static final int CHANNEL_OUT_FRONT_LEFT = 0x4;
     public static final int CHANNEL_OUT_FRONT_RIGHT = 0x8;
     public static final int CHANNEL_OUT_FRONT_CENTER = 0x10;
@@ -64,6 +65,25 @@
     public static final int CHANNEL_OUT_FRONT_LEFT_OF_CENTER = 0x100;
     public static final int CHANNEL_OUT_FRONT_RIGHT_OF_CENTER = 0x200;
     public static final int CHANNEL_OUT_BACK_CENTER = 0x400;
+    /** @hide */
+    public static final int CHANNEL_OUT_SIDE_LEFT =         0x800;
+    /** @hide */
+    public static final int CHANNEL_OUT_SIDE_RIGHT =       0x1000;
+    /** @hide */
+    public static final int CHANNEL_OUT_TOP_CENTER =       0x2000;
+    /** @hide */
+    public static final int CHANNEL_OUT_TOP_FRONT_LEFT =   0x4000;
+    /** @hide */
+    public static final int CHANNEL_OUT_TOP_FRONT_CENTER = 0x8000;
+    /** @hide */
+    public static final int CHANNEL_OUT_TOP_FRONT_RIGHT = 0x10000;
+    /** @hide */
+    public static final int CHANNEL_OUT_TOP_BACK_LEFT =   0x20000;
+    /** @hide */
+    public static final int CHANNEL_OUT_TOP_BACK_CENTER = 0x40000;
+    /** @hide */
+    public static final int CHANNEL_OUT_TOP_BACK_RIGHT =  0x80000;
+
     public static final int CHANNEL_OUT_MONO = CHANNEL_OUT_FRONT_LEFT;
     public static final int CHANNEL_OUT_STEREO = (CHANNEL_OUT_FRONT_LEFT | CHANNEL_OUT_FRONT_RIGHT);
     public static final int CHANNEL_OUT_QUAD = (CHANNEL_OUT_FRONT_LEFT | CHANNEL_OUT_FRONT_RIGHT |
@@ -75,6 +95,12 @@
     public static final int CHANNEL_OUT_7POINT1 = (CHANNEL_OUT_FRONT_LEFT | CHANNEL_OUT_FRONT_RIGHT |
             CHANNEL_OUT_FRONT_CENTER | CHANNEL_OUT_LOW_FREQUENCY | CHANNEL_OUT_BACK_LEFT | CHANNEL_OUT_BACK_RIGHT |
             CHANNEL_OUT_FRONT_LEFT_OF_CENTER | CHANNEL_OUT_FRONT_RIGHT_OF_CENTER);
+    /** @hide */
+    public static final int CHANNEL_OUT_7POINT1_SURROUND = (
+            CHANNEL_OUT_FRONT_LEFT | CHANNEL_OUT_FRONT_CENTER | CHANNEL_OUT_FRONT_RIGHT |
+            CHANNEL_OUT_SIDE_LEFT | CHANNEL_OUT_SIDE_RIGHT |
+            CHANNEL_OUT_BACK_LEFT | CHANNEL_OUT_BACK_RIGHT |
+            CHANNEL_OUT_LOW_FREQUENCY);
 
     public static final int CHANNEL_IN_DEFAULT = 1;
     public static final int CHANNEL_IN_LEFT = 0x4;
diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java
index 482b437..95671bc 100644
--- a/media/java/android/media/MediaPlayer.java
+++ b/media/java/android/media/MediaPlayer.java
@@ -611,7 +611,7 @@
      * needed.  Not calling this method when playing back a video will
      * result in only the audio track being played.
      *
-     * Either a surface or surface texture must be set if a display or video sink
+     * Either a surface holder or surface must be set if a display or video sink
      * is needed.  Not calling this method or {@link #setTexture(SurfaceTexture)}
      * when playing back a video will result in only the audio track being played.
      *
@@ -630,6 +630,27 @@
     }
 
     /**
+     * Sets the {@link Surface} to be used as the sink for the video portion of
+     * the media. This is similar to {@link #setDisplay(SurfaceHolder)}, but does not
+     * support {@link #setScreenOnWhilePlaying(boolean)} or {@link #updateSurfaceScreenOn()}.
+     * Setting a Surface will un-set any Surface or SurfaceHolder that was previously set.
+     *
+     * @param surface The {@link Surface} to be used for the video portion of the media.
+     *
+     * @hide Pending review by API council.
+     */
+    public void setSurface(Surface surface) {
+        if (mScreenOnWhilePlaying && surface != null && mSurface != null) {
+            Log.w(TAG, "setScreenOnWhilePlaying(true) is ineffective for Surface");
+        }
+        mSurfaceHolder = null;
+        mSurface = surface;
+        mParcelSurfaceTexture = null;  // TODO(tedbo): Remove.
+        _setVideoSurfaceOrSurfaceTexture();
+        updateSurfaceScreenOn();
+    }
+
+    /**
      * Sets the {@link SurfaceTexture} to be used as the sink for the
      * video portion of the media. Either a surface or surface texture
      * must be set if a video sink is needed.  The same surface texture
@@ -665,7 +686,7 @@
      * @param pst The {@link ParcelSurfaceTexture} to be used as the sink for
      * the video portion of the media.
      *
-     * @hide Pending review by API council.
+     * @hide Pending removal when there are no more callers.
      */
     public void setParcelSurfaceTexture(ParcelSurfaceTexture pst) {
         if (mScreenOnWhilePlaying && pst != null && mParcelSurfaceTexture == null) {
@@ -1000,8 +1021,8 @@
      */
     public void setScreenOnWhilePlaying(boolean screenOn) {
         if (mScreenOnWhilePlaying != screenOn) {
-            if (screenOn && mParcelSurfaceTexture != null) {
-                Log.w(TAG, "setScreenOnWhilePlaying(true) is ineffective for SurfaceTexture");
+            if (screenOn && mSurfaceHolder == null) {
+                Log.w(TAG, "setScreenOnWhilePlaying(true) is ineffective without a SurfaceHolder");
             }
             mScreenOnWhilePlaying = screenOn;
             updateSurfaceScreenOn();
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 082dab3..fc8ab96 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -158,7 +158,7 @@
     <!-- Checkbox label for application compatibility mode OFF (normal mode on tablets).
          [CHAR LIMIT=25] -->
     <string name="compat_mode_off">Stretch to fill screen</string>
-    
+
     <!-- Compatibility mode help screen: header text. [CHAR LIMIT=50] -->
     <string name="compat_mode_help_header">Compatibility Zoom</string>
 
@@ -168,7 +168,7 @@
     <!-- toast message displayed when a screenshot is saved to the Gallery. -->
     <string name="screenshot_saving_toast">Screenshot saved to Gallery</string>
     <!-- toast message displayed when we fail to take a screenshot. -->
-    <string name="screenshot_failed_toast">Could not save screenshot</string>
+    <string name="screenshot_failed_toast">Could not save screenshot. External storage may be in use.</string>
 
     <!-- Title for the USB function chooser in UsbPreferenceActivity. [CHAR LIMIT=30] -->
     <string name="usb_preference_title">USB file transfer options</string>
@@ -299,5 +299,4 @@
 
     <!-- Content description of the ringer silent icon in the notification panel for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
     <string name="accessibility_ringer_silent">Ringer silent.</string>
-
 </resources>
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
index 83a5578..02a955b 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
@@ -87,7 +87,7 @@
         Context context = params[0].context;
         Bitmap image = params[0].image;
 
-        try{
+        try {
             long currentTime = System.currentTimeMillis();
             String date = new SimpleDateFormat("MM-dd-yy-kk-mm-ss").format(new Date(currentTime));
             String imageDir = Environment.getExternalStoragePublicDirectory(
@@ -114,7 +114,9 @@
             out.close();
 
             params[0].result = 0;
-        }catch(IOException e){
+        } catch (Exception e) {
+            // IOException/UnsupportedOperationException may be thrown if external storage is not
+            // mounted
             params[0].result = 1;
         }
 
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindow.java b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
index e0debf7..bfc3cdd 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindow.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
@@ -2040,13 +2040,14 @@
                         mActionModePopup = new PopupWindow(mContext, null,
                                 com.android.internal.R.attr.actionModePopupWindowStyle);
                         mActionModePopup.setLayoutInScreenEnabled(true);
+                        mActionModePopup.setLayoutInsetDecor(true);
                         mActionModePopup.setClippingEnabled(false);
                         mActionModePopup.setContentView(mActionModeView);
                         mActionModePopup.setWidth(MATCH_PARENT);
 
                         TypedValue heightValue = new TypedValue();
                         mContext.getTheme().resolveAttribute(
-                                com.android.internal.R.attr.actionBarSize, heightValue, false);
+                                com.android.internal.R.attr.actionBarSize, heightValue, true);
                         final int height = TypedValue.complexToDimensionPixelSize(heightValue.data,
                                 mContext.getResources().getDisplayMetrics());
                         mActionModePopup.setHeight(height);
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index ae13ab5..b7f6adf 100755
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -2444,20 +2444,22 @@
         switch (keyCode) {
             case KeyEvent.KEYCODE_VOLUME_DOWN:
                 if (down) {
-                    // If the power key down was already triggered, take the screenshot
-                    if (mPowerDownTriggered) {
-                        // Dismiss the power-key longpress
-                        mHandler.removeCallbacks(mPowerLongPress);
-                        mPowerKeyHandled = true;
+                    if (isScreenOn) {
+                        // If the power key down was already triggered, take the screenshot
+                        if (mPowerDownTriggered) {
+                            // Dismiss the power-key longpress
+                            mHandler.removeCallbacks(mPowerLongPress);
+                            mPowerKeyHandled = true;
 
-                        // Take the screenshot
-                        takeScreenshot();
+                            // Take the screenshot
+                            takeScreenshot();
 
-                        // Prevent the event from being passed through to the current activity
-                        result &= ~ACTION_PASS_TO_USER;
-                        break;
+                            // Prevent the event from being passed through to the current activity
+                            result &= ~ACTION_PASS_TO_USER;
+                            break;
+                        }
+                        mVolumeDownTriggered = true;
                     }
-                    mVolumeDownTriggered = true;
                 } else {
                     mVolumeDownTriggered = false;
                 }
@@ -2541,17 +2543,18 @@
             case KeyEvent.KEYCODE_POWER: {
                 result &= ~ACTION_PASS_TO_USER;
                 if (down) {
-                    // If the volume down key has been triggered, then just take the screenshot
-                    if (mVolumeDownTriggered) {
-                        // Take the screenshot
-                        takeScreenshot();
-                        mPowerKeyHandled = true;
+                    if (isScreenOn) {
+                        // If the volume down key has been triggered, then just take the screenshot
+                        if (mVolumeDownTriggered) {
+                            // Take the screenshot
+                            takeScreenshot();
+                            mPowerKeyHandled = true;
 
-                        // Prevent the event from being passed through to the current activity
-                        break;
+                            // Prevent the event from being passed through to the current activity
+                            break;
+                        }
+                        mPowerDownTriggered = true;
                     }
-                    mPowerDownTriggered = true;
-
 
                     ITelephony telephonyService = getTelephonyService();
                     boolean hungUp = false;
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index 0323fe0..cb1f921 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -1043,6 +1043,25 @@
     return NO_ERROR;
 }
 
+status_t AudioFlinger::ThreadBase::dumpEffectChains(int fd, const Vector<String16>& args)
+{
+    const size_t SIZE = 256;
+    char buffer[SIZE];
+    String8 result;
+
+    snprintf(buffer, SIZE, "\n- %d Effect Chains:\n", mEffectChains.size());
+    write(fd, buffer, strlen(buffer));
+
+    for (size_t i = 0; i < mEffectChains.size(); ++i) {
+        sp<EffectChain> chain = mEffectChains[i];
+        if (chain != 0) {
+            chain->dump(fd, args);
+        }
+    }
+    return NO_ERROR;
+}
+
+
 // ----------------------------------------------------------------------------
 
 AudioFlinger::PlaybackThread::PlaybackThread(const sp<AudioFlinger>& audioFlinger,
@@ -1111,24 +1130,6 @@
     return NO_ERROR;
 }
 
-status_t AudioFlinger::PlaybackThread::dumpEffectChains(int fd, const Vector<String16>& args)
-{
-    const size_t SIZE = 256;
-    char buffer[SIZE];
-    String8 result;
-
-    snprintf(buffer, SIZE, "\n- %d Effect Chains:\n", mEffectChains.size());
-    write(fd, buffer, strlen(buffer));
-
-    for (size_t i = 0; i < mEffectChains.size(); ++i) {
-        sp<EffectChain> chain = mEffectChains[i];
-        if (chain != 0) {
-            chain->dump(fd, args);
-        }
-    }
-    return NO_ERROR;
-}
-
 status_t AudioFlinger::PlaybackThread::dumpInternals(int fd, const Vector<String16>& args)
 {
     const size_t SIZE = 256;
@@ -4178,6 +4179,7 @@
     write(fd, result.string(), result.size());
 
     dumpBase(fd, args);
+    dumpEffectChains(fd, args);
 
     return NO_ERROR;
 }
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
index fff4f06..e2cf946 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -285,6 +285,7 @@
         };
 
         status_t dumpBase(int fd, const Vector<String16>& args);
+        status_t dumpEffectChains(int fd, const Vector<String16>& args);
 
         // base for record and playback
         class TrackBase : public AudioBufferProvider, public RefBase {
@@ -724,7 +725,6 @@
 
         virtual status_t    dumpInternals(int fd, const Vector<String16>& args);
         status_t    dumpTracks(int fd, const Vector<String16>& args);
-        status_t    dumpEffectChains(int fd, const Vector<String16>& args);
 
         SortedVector< sp<Track> >       mTracks;
         // mStreamTypes[] uses 1 additionnal stream type internally for the OutputTrack used by DuplicatingThread
diff --git a/services/java/com/android/server/TextServicesManagerService.java b/services/java/com/android/server/TextServicesManagerService.java
index 4a0c837..ffdc288 100644
--- a/services/java/com/android/server/TextServicesManagerService.java
+++ b/services/java/com/android/server/TextServicesManagerService.java
@@ -156,6 +156,9 @@
             final String curSpellCheckerId =
                     Settings.Secure.getString(mContext.getContentResolver(),
                             Settings.Secure.SPELL_CHECKER_SERVICE);
+            if (DBG) {
+                Slog.w(TAG, "getCurrentSpellChecker: " + curSpellCheckerId);
+            }
             if (TextUtils.isEmpty(curSpellCheckerId)) {
                 return null;
             }
@@ -198,6 +201,11 @@
     }
 
     @Override
+    public SpellCheckerInfo[] getEnabledSpellCheckers() {
+        return mSpellCheckerList.toArray(new SpellCheckerInfo[mSpellCheckerList.size()]);
+    }
+
+    @Override
     public void finishSpellCheckerService(ISpellCheckerSessionListener listener) {
         synchronized(mSpellCheckerMap) {
             for (SpellCheckerBindGroup group : mSpellCheckerBindGroups.values()) {
@@ -208,6 +216,9 @@
     }
 
     private void setCurrentSpellChecker(SpellCheckerInfo sci) {
+        if (DBG) {
+            Slog.w(TAG, "setCurrentSpellChecker: " + sci.getId());
+        }
         if (sci == null || mSpellCheckerMap.containsKey(sci.getId())) return;
         Settings.Secure.putString(mContext.getContentResolver(),
                 Settings.Secure.SPELL_CHECKER_SERVICE, sci == null ? "" : sci.getId());
diff --git a/services/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/java/com/android/server/accessibility/AccessibilityManagerService.java
index bb9d15b..92647e6 100644
--- a/services/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -49,6 +49,7 @@
 import android.view.IWindow;
 import android.view.View;
 import android.view.accessibility.AccessibilityEvent;
+import android.view.accessibility.AccessibilityManager;
 import android.view.accessibility.AccessibilityNodeInfo;
 import android.view.accessibility.IAccessibilityInteractionConnection;
 import android.view.accessibility.IAccessibilityInteractionConnectionCallback;
@@ -129,10 +130,10 @@
 
     private boolean mIsAccessibilityEnabled;
 
-    private boolean mIsTouchExplorationRequested;
-
     private AccessibilityInputFilter mInputFilter;
 
+    private boolean mHasInputFilter;
+
     private final List<AccessibilityServiceInfo> mEnabledServicesForFeedbackTempList = new ArrayList<AccessibilityServiceInfo>();
 
     private boolean mIsTouchExplorationEnabled;
@@ -189,7 +190,7 @@
                     manageServicesLocked();
                 }
             }
-            
+
             @Override
             public boolean onHandleForceStop(Intent intent, String[] packages,
                     int uid, boolean doit) {
@@ -236,17 +237,16 @@
                         mIsAccessibilityEnabled = Settings.Secure.getInt(
                                 mContext.getContentResolver(),
                                 Settings.Secure.ACCESSIBILITY_ENABLED, 0) == 1;
-                        // if accessibility is enabled inform our clients we are on
-                        if (mIsAccessibilityEnabled) {
-                            sendAccessibilityEnabledToClientsLocked();
-                        }
+
                         manageServicesLocked();
 
                         // get touch exploration enabled setting on boot
-                        mIsTouchExplorationRequested = Settings.Secure.getInt(
+                        mIsTouchExplorationEnabled = Settings.Secure.getInt(
                                 mContext.getContentResolver(),
-                                Settings.Secure.TOUCH_EXPLORATION_REQUESTED, 0) == 1;
-                        updateTouchExplorationEnabledLocked();
+                                Settings.Secure.TOUCH_EXPLORATION_ENABLED, 0) == 1;
+                        updateInputFilterLocked();
+
+                        sendStateToClientsLocked();
                     }
                     
                     return;
@@ -288,13 +288,13 @@
                         } else {
                             unbindAllServicesLocked();
                         }
-                        sendAccessibilityEnabledToClientsLocked();
+                        sendStateToClientsLocked();
                     }
                 }
             });
 
         Uri touchExplorationRequestedUri = Settings.Secure.getUriFor(
-                Settings.Secure.TOUCH_EXPLORATION_REQUESTED);
+                Settings.Secure.TOUCH_EXPLORATION_ENABLED);
         contentResolver.registerContentObserver(touchExplorationRequestedUri, false,
                 new ContentObserver(new Handler()) {
                     @Override
@@ -302,10 +302,11 @@
                         super.onChange(selfChange);
 
                         synchronized (mLock) {
-                            mIsTouchExplorationRequested = Settings.Secure.getInt(
+                            mIsTouchExplorationEnabled = Settings.Secure.getInt(
                                     mContext.getContentResolver(),
-                                    Settings.Secure.TOUCH_EXPLORATION_REQUESTED, 0) == 1;
-                            updateTouchExplorationEnabledLocked();
+                                    Settings.Secure.TOUCH_EXPLORATION_ENABLED, 0) == 1;
+                            updateInputFilterLocked();
+                            sendStateToClientsLocked();
                         }
                     }
                 });
@@ -325,7 +326,7 @@
             });
     }
 
-    public boolean addClient(IAccessibilityManagerClient client) throws RemoteException {
+    public int addClient(IAccessibilityManagerClient client) throws RemoteException {
         synchronized (mLock) {
             final IAccessibilityManagerClient addedClient = client;
             mClients.add(addedClient);
@@ -338,7 +339,7 @@
                     }
                 }
             }, 0);
-            return mIsAccessibilityEnabled;
+            return getState();
         }
     }
 
@@ -628,7 +629,7 @@
             service.linkToOwnDeath();
             mServices.add(service);
             mComponentNameToServiceMap.put(service.mComponentName, service);
-            updateTouchExplorationEnabledLocked();
+            updateInputFilterLocked();
         } catch (RemoteException e) {
             /* do nothing */
         }
@@ -648,7 +649,7 @@
         mComponentNameToServiceMap.remove(service.mComponentName);
         mHandler.removeMessages(service.mId);
         service.unlinkToOwnDeath();
-        updateTouchExplorationEnabledLocked();
+        updateInputFilterLocked();
         return removed;
     }
 
@@ -781,12 +782,13 @@
     }
 
     /**
-     * Updates the state of {@link android.view.accessibility.AccessibilityManager} clients.
+     * Sends the state to the clients.
      */
-    private void sendAccessibilityEnabledToClientsLocked() {
+    private void sendStateToClientsLocked() {
+        final int state = getState();
         for (int i = 0, count = mClients.size(); i < count; i++) {
             try {
-                mClients.get(i).setEnabled(mIsAccessibilityEnabled);
+                mClients.get(i).setState(state);
             } catch (RemoteException re) {
                 mClients.remove(i);
                 count--;
@@ -796,48 +798,39 @@
     }
 
     /**
-     * Sends the touch exploration state to clients.
+     * Gets the current state as a set of flags.
+     *
+     * @return The state.
      */
-    private void sendTouchExplorationEnabledToClientsLocked() {
-        for (int i = 0, count = mClients.size(); i < count; i++) {
-            try {
-                mClients.get(i).setTouchExplorationEnabled(mIsTouchExplorationEnabled);
-            } catch (RemoteException re) {
-                mClients.remove(i);
-                count--;
-                i--;
-            }
+    private int getState() {
+        int state = 0;
+        if (mIsAccessibilityEnabled) {
+            state |= AccessibilityManager.STATE_FLAG_ACCESSIBILITY_ENABLED;
         }
+        // Touch exploration relies on enabled accessibility.
+        if (mIsAccessibilityEnabled && mIsTouchExplorationEnabled) {
+            state |= AccessibilityManager.STATE_FLAG_TOUCH_EXPLORATION_ENABLED;
+        }
+        return state;
     }
 
     /**
-     * Updates the touch exploration state. Touch exploration is enabled if it
-     * is requested, accessibility is on and there is at least one enabled
-     * accessibility service providing spoken feedback.
+     * Updates the touch exploration state.
      */
-    private void updateTouchExplorationEnabledLocked() {
-        if (mIsAccessibilityEnabled && mIsTouchExplorationRequested) {
-            final boolean hasSpeakingServicesEnabled = !getEnabledAccessibilityServiceList(
-                     AccessibilityServiceInfo.FEEDBACK_SPOKEN).isEmpty();
-            if (!mIsTouchExplorationEnabled) {
-                if (!hasSpeakingServicesEnabled) {
-                     return;
-                }
+    private void updateInputFilterLocked() {
+        if (mIsAccessibilityEnabled && mIsTouchExplorationEnabled) {
+            if (!mHasInputFilter) {
+                mHasInputFilter = true;
                 if (mInputFilter == null) {
                     mInputFilter = new AccessibilityInputFilter(mContext);
                 }
                 mWindowManagerService.setInputFilter(mInputFilter);
-                mIsTouchExplorationEnabled = true;
-                sendTouchExplorationEnabledToClientsLocked();
-                return;
-            } else if (hasSpeakingServicesEnabled) {
-                return;
             }
+            return;
         }
-        if (mIsTouchExplorationEnabled) {
+        if (mHasInputFilter) {
+            mHasInputFilter = false;
             mWindowManagerService.setInputFilter(null);
-            mIsTouchExplorationEnabled = false;
-            sendTouchExplorationEnabledToClientsLocked();
         }
     }
 
diff --git a/services/java/com/android/server/accessibility/TouchExplorer.java b/services/java/com/android/server/accessibility/TouchExplorer.java
index 5a3a55d..0ad58d0 100644
--- a/services/java/com/android/server/accessibility/TouchExplorer.java
+++ b/services/java/com/android/server/accessibility/TouchExplorer.java
@@ -19,21 +19,21 @@
 import static android.view.accessibility.AccessibilityEvent.TYPE_TOUCH_EXPLORATION_GESTURE_END;
 import static android.view.accessibility.AccessibilityEvent.TYPE_TOUCH_EXPLORATION_GESTURE_START;
 
-import com.android.server.accessibility.AccessibilityInputFilter.Explorer;
-import com.android.server.wm.InputFilter;
-
 import android.content.Context;
 import android.os.Handler;
 import android.os.SystemClock;
 import android.util.Slog;
 import android.view.MotionEvent;
-import android.view.ViewConfiguration;
-import android.view.WindowManagerPolicy;
 import android.view.MotionEvent.PointerCoords;
 import android.view.MotionEvent.PointerProperties;
+import android.view.ViewConfiguration;
+import android.view.WindowManagerPolicy;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityManager;
 
+import com.android.server.accessibility.AccessibilityInputFilter.Explorer;
+import com.android.server.wm.InputFilter;
+
 import java.util.Arrays;
 
 /**
@@ -146,6 +146,9 @@
     // Command for delayed sending of a hover event.
     private final SendHoverDelayed mSendHoverDelayed;
 
+    // Command for delayed sending of a long press.
+    private final PerformLongPressDelayed mPerformLongPressDelayed;
+
     /**
      * Creates a new instance.
      *
@@ -160,6 +163,7 @@
         mPointerTracker = new PointerTracker(context);
         mHandler = new Handler(context.getMainLooper());
         mSendHoverDelayed = new SendHoverDelayed();
+        mPerformLongPressDelayed = new PerformLongPressDelayed();
         mAccessibilityManager = AccessibilityManager.getInstance(context);
     }
 
@@ -208,15 +212,7 @@
         final int activePointerCount = pointerTracker.getActivePointerCount();
 
         switch (event.getActionMasked()) {
-            case MotionEvent.ACTION_DOWN: {
-                // Send a hover for every finger down so the user gets feedback
-                // where she is currently touching.
-                mSendHoverDelayed.forceSendAndRemove();
-                final int pointerIndex = event.getActionIndex();
-                final int pointerIdBits = (1 << event.getPointerId(pointerIndex));
-                mSendHoverDelayed.post(event, MotionEvent.ACTION_HOVER_ENTER, pointerIdBits,
-                        policyFlags, DELAY_SEND_HOVER_MOVE);
-            } break;
+            case MotionEvent.ACTION_DOWN:
             case MotionEvent.ACTION_POINTER_DOWN: {
                 switch (activePointerCount) {
                     case 0: {
@@ -224,13 +220,13 @@
                                 + "touch exploring state!");
                     }
                     case 1: {
-                        // Schedule a hover event which will lead to firing an
-                        // accessibility event from the hovered view.
-                        mSendHoverDelayed.remove();
+                        // Send hover if pending.
+                        mSendHoverDelayed.forceSendAndRemove();
+                        // Send a hover for every finger down so the user gets feedback.
                         final int pointerId = pointerTracker.getPrimaryActivePointerId();
                         final int pointerIdBits = (1 << pointerId);
                         final int lastAction = pointerTracker.getLastInjectedHoverAction();
-                        // If a schedules hover enter for another pointer is delivered we send move.
+                        // If a hover enter for another pointer is delivered we send move.
                         final int action = (lastAction == MotionEvent.ACTION_HOVER_ENTER)
                                 ? MotionEvent.ACTION_HOVER_MOVE
                                 : MotionEvent.ACTION_HOVER_ENTER;
@@ -244,7 +240,19 @@
                         // If more pointers down on the screen since the last touch
                         // exploration we discard the last cached touch explore event.
                         if (event.getPointerCount() != mLastTouchExploreEvent.getPointerCount()) {
-                           mLastTouchExploreEvent = null;
+                            mLastTouchExploreEvent = null;
+                            break;
+                        }
+
+                        // If the down is in the time slop => schedule a long press.
+                        final long pointerDownTime =
+                            pointerTracker.getReceivedPointerDownTime(pointerId);
+                        final long lastExploreTime = mLastTouchExploreEvent.getEventTime();
+                        final long deltaTimeExplore = pointerDownTime - lastExploreTime;
+                        if (deltaTimeExplore <= ACTIVATION_TIME_SLOP) {
+                            mPerformLongPressDelayed.post(event, policyFlags,
+                                    ViewConfiguration.getLongPressTimeout());
+                            break;
                         }
                     } break;
                     default: {
@@ -275,6 +283,7 @@
                                 sendAccessibilityEvent(TYPE_TOUCH_EXPLORATION_GESTURE_START);
                                 // Make sure the scheduled down/move event is sent.
                                 mSendHoverDelayed.forceSendAndRemove();
+                                mPerformLongPressDelayed.remove();
                                 // If we have transitioned to exploring state from another one
                                 // we need to send a hover enter event here.
                                 final int lastAction = mPointerTracker.getLastInjectedHoverAction();
@@ -291,20 +300,11 @@
                                     policyFlags);
                         }
 
-                        // Detect long press on the last touch explored position.
-                        if (!mTouchExploreGestureInProgress && mLastTouchExploreEvent != null) {
+                        // If the exploring pointer moved enough => cancel the long press.
+                        if (!mTouchExploreGestureInProgress && mLastTouchExploreEvent != null
+                                && mPerformLongPressDelayed.isPenidng()) {
 
-                            // If the down was not in the time slop => nothing else to do.
-                            final long pointerDownTime =
-                                pointerTracker.getReceivedPointerDownTime(pointerId);
-                            final long lastExploreTime = mLastTouchExploreEvent.getEventTime();
-                            final long deltaTimeExplore = pointerDownTime - lastExploreTime;
-                            if (deltaTimeExplore > ACTIVATION_TIME_SLOP) {
-                                mLastTouchExploreEvent = null;
-                                break;
-                            }
-
-                            // If the pointer moved more than the tap slop => nothing else to do.
+                            // If the pointer moved more than the tap slop => cancel long press.
                             final float deltaX = mLastTouchExploreEvent.getX(pointerIndex)
                                     - event.getX(pointerIndex);
                             final float deltaY = mLastTouchExploreEvent.getY(pointerIndex)
@@ -312,24 +312,14 @@
                             final float moveDelta = (float) Math.hypot(deltaX, deltaY);
                             if (moveDelta > mTouchExplorationTapSlop) {
                                 mLastTouchExploreEvent = null;
+                                mPerformLongPressDelayed.remove();
                                break;
                             }
-
-                            // If down for long enough we get a long press.
-                            final long deltaTimeMove = event.getEventTime() - pointerDownTime;
-                            if (deltaTimeMove > ViewConfiguration.getLongPressTimeout()) {
-                                mCurrentState = STATE_DELEGATING;
-                                // Make sure the scheduled hover exit is delivered.
-                                mSendHoverDelayed.forceSendAndRemove();
-                                sendDownForAllActiveNotInjectedPointers(event, policyFlags);
-                                sendMotionEvent(event, policyFlags);
-                                mTouchExploreGestureInProgress = false;
-                                mLastTouchExploreEvent = null;
-                            }
                         }
                     } break;
                     case 2: {
                         mSendHoverDelayed.forceSendAndRemove();
+                        mPerformLongPressDelayed.remove();
                         // We want to no longer hover over the location so subsequent
                         // touch at the same spot will generate a hover enter.
                         sendMotionEvent(event, MotionEvent.ACTION_HOVER_EXIT, pointerIdBits,
@@ -360,6 +350,7 @@
                     } break;
                     default: {
                         mSendHoverDelayed.forceSendAndRemove();
+                        mPerformLongPressDelayed.remove();
                         // We want to no longer hover over the location so subsequent
                         // touch at the same spot will generate a hover enter.
                         sendMotionEvent(event, MotionEvent.ACTION_HOVER_EXIT, pointerIdBits,
@@ -388,22 +379,26 @@
                             break;
                         }
 
+                        mSendHoverDelayed.forceSendAndRemove();
+                        mPerformLongPressDelayed.remove();
+
                         // If touch exploring announce the end of the gesture.
+                        // Also do not click on the last explored location.
                         if (mTouchExploreGestureInProgress) {
-                            sendAccessibilityEvent(TYPE_TOUCH_EXPLORATION_GESTURE_END);
                             mTouchExploreGestureInProgress = false;
+                            mLastTouchExploreEvent = MotionEvent.obtain(event);
+                            sendAccessibilityEvent(TYPE_TOUCH_EXPLORATION_GESTURE_END);
+                            break;
                         }
 
                         // Detect whether to activate i.e. click on the last explored location.
                         if (mLastTouchExploreEvent != null) {
-
                             // If the down was not in the time slop => nothing else to do.
                             final long eventTime =
                                 pointerTracker.getLastReceivedUpPointerDownTime();
                             final long exploreTime = mLastTouchExploreEvent.getEventTime();
                             final long deltaTime = eventTime - exploreTime;
                             if (deltaTime > ACTIVATION_TIME_SLOP) {
-                                mSendHoverDelayed.forceSendAndRemove();
                                 final int lastAction = mPointerTracker.getLastInjectedHoverAction();
                                 if (lastAction != MotionEvent.ACTION_HOVER_EXIT) {
                                     sendMotionEvent(event, MotionEvent.ACTION_HOVER_EXIT,
@@ -413,15 +408,14 @@
                                 break;
                             }
 
-                            // If the pointer moved more than the tap slop => nothing else to do.
+                            // If a tap is farther than the tap slop => nothing to do.
                             final int pointerIndex = event.findPointerIndex(pointerId);
-                            final float deltaX = pointerTracker.getLastReceivedUpPointerDownX()
+                            final float deltaX = mLastTouchExploreEvent.getX(pointerIndex)
                                     - event.getX(pointerIndex);
-                            final float deltaY = pointerTracker.getLastReceivedUpPointerDownY()
+                            final float deltaY = mLastTouchExploreEvent.getY(pointerIndex)
                                     - event.getY(pointerIndex);
                             final float deltaMove = (float) Math.hypot(deltaX, deltaY);
                             if (deltaMove > mTouchExplorationTapSlop) {
-                                mSendHoverDelayed.forceSendAndRemove();
                                 final int lastAction = mPointerTracker.getLastInjectedHoverAction();
                                 if (lastAction != MotionEvent.ACTION_HOVER_EXIT) {
                                     sendMotionEvent(event, MotionEvent.ACTION_HOVER_EXIT,
@@ -432,7 +426,6 @@
                             }
 
                             // All preconditions are met, so click the last explored location.
-                            mSendHoverDelayed.forceSendAndRemove();
                             sendActionDownAndUp(mLastTouchExploreEvent, policyFlags);
                             mLastTouchExploreEvent = null;
                         } else {
@@ -448,6 +441,8 @@
                 }
             } break;
             case MotionEvent.ACTION_CANCEL: {
+                mSendHoverDelayed.remove();
+                mPerformLongPressDelayed.remove();
                 final int lastAction = pointerTracker.getLastInjectedHoverAction();
                 if (lastAction != MotionEvent.ACTION_HOVER_EXIT) {
                     final int pointerId = pointerTracker.getPrimaryActivePointerId();
@@ -934,8 +929,6 @@
         private int mInjectedPointersDown;
 
         // Keep track of the last up pointer data.
-        private float mLastReceivedUpPointerDownX;
-        private float mLastReveivedUpPointerDownY;
         private long mLastReceivedUpPointerDownTime;
         private int mLastReceivedUpPointerId;
         private boolean mLastReceivedUpPointerActive;
@@ -968,8 +961,6 @@
             mPrimaryActivePointerId = 0;
             mHasMovingActivePointer = false;
             mInjectedPointersDown = 0;
-            mLastReceivedUpPointerDownX = 0;
-            mLastReveivedUpPointerDownY = 0;
             mLastReceivedUpPointerDownTime = 0;
             mLastReceivedUpPointerId = 0;
             mLastReceivedUpPointerActive = false;
@@ -1126,20 +1117,6 @@
         }
 
         /**
-         * @return The X coordinate where the last up received pointer went down.
-         */
-        public float getLastReceivedUpPointerDownX() {
-            return mLastReceivedUpPointerDownX;
-        }
-
-        /**
-         * @return The Y coordinate where the last up received pointer went down.
-         */
-        public float getLastReceivedUpPointerDownY() {
-            return mLastReveivedUpPointerDownY;
-        }
-
-        /**
          * @return The time when the last up received pointer went down.
          */
         public long getLastReceivedUpPointerDownTime() {
@@ -1220,8 +1197,6 @@
             final int pointerFlag = (1 << pointerId);
 
             mLastReceivedUpPointerId = 0;
-            mLastReceivedUpPointerDownX = 0;
-            mLastReveivedUpPointerDownY = 0;
             mLastReceivedUpPointerDownTime = 0;
             mLastReceivedUpPointerActive = false;
 
@@ -1262,8 +1237,6 @@
             final int pointerFlag = (1 << pointerId);
 
             mLastReceivedUpPointerId = pointerId;
-            mLastReceivedUpPointerDownX = getReceivedPointerDownX(pointerId);
-            mLastReveivedUpPointerDownY = getReceivedPointerDownY(pointerId);
             mLastReceivedUpPointerDownTime = getReceivedPointerDownTime(pointerId);
             mLastReceivedUpPointerActive = isActivePointer(pointerId);
 
@@ -1400,6 +1373,51 @@
     }
 
     /**
+     * Class for delayed sending of long press.
+     */
+    private final class PerformLongPressDelayed implements Runnable {
+        private MotionEvent mEvent;
+        private int mPolicyFlags;
+
+        public void post(MotionEvent prototype, int policyFlags, long delay) {
+            mEvent = MotionEvent.obtain(prototype);
+            mPolicyFlags = policyFlags;
+            mHandler.postDelayed(this, delay);
+        }
+
+        public void remove() {
+            if (isPenidng()) {
+                mHandler.removeCallbacks(this);
+                clear();
+            }
+        }
+
+        private boolean isPenidng() {
+            return (mEvent != null);
+        }
+
+        @Override
+        public void run() {
+            mCurrentState = STATE_DELEGATING;
+            // Make sure the scheduled hover exit is delivered.
+            mSendHoverDelayed.forceSendAndRemove();
+            sendDownForAllActiveNotInjectedPointers(mEvent, mPolicyFlags);
+            mTouchExploreGestureInProgress = false;
+            mLastTouchExploreEvent = null;
+            clear();
+        }
+
+        private void clear() {
+            if (!isPenidng()) {
+                return;
+            }
+            mEvent.recycle();
+            mEvent = null;
+            mPolicyFlags = 0;
+        }
+    }
+
+    /**
      * Class for delayed sending of hover events.
      */
     private final class SendHoverDelayed implements Runnable {
diff --git a/services/tests/servicestests/src/com/android/server/AccessibilityManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/AccessibilityManagerServiceTest.java
index 1234bfd..46bcc4a 100644
--- a/services/tests/servicestests/src/com/android/server/AccessibilityManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/AccessibilityManagerServiceTest.java
@@ -29,12 +29,13 @@
 import android.test.AndroidTestCase;
 import android.test.suitebuilder.annotation.LargeTest;
 import android.view.accessibility.AccessibilityEvent;
+import android.view.accessibility.AccessibilityManager;
 import android.view.accessibility.IAccessibilityManager;
 import android.view.accessibility.IAccessibilityManagerClient;
 
 /**
  * This test exercises the
- * {@link com.android.server.AccessibilityManagerService} by mocking the
+ * {@link com.android.server.accessibility.AccessibilityManagerService} by mocking the
  * {@link android.view.accessibility.AccessibilityManager} which talks to to the
  * service. The service itself is interacting with the platform. Note: Testing
  * the service in full isolation would require significant amount of work for
@@ -97,7 +98,9 @@
         MyMockAccessibilityManagerClient mockClient = new MyMockAccessibilityManagerClient();
 
         // invoke the method under test
-        boolean enabledAccessibilityDisabled = mManagerService.addClient(mockClient);
+        final int stateFlagsDisabled = mManagerService.addClient(mockClient);
+        boolean enabledAccessibilityDisabled =
+            (stateFlagsDisabled & AccessibilityManager.STATE_FLAG_ACCESSIBILITY_ENABLED) != 0;
 
         // check expected result
         assertFalse("The client must be disabled since accessibility is disabled.",
@@ -107,7 +110,10 @@
         ensureAccessibilityEnabled(mContext, true);
 
         // invoke the method under test
-        boolean enabledAccessibilityEnabled = mManagerService.addClient(mockClient);
+        final int stateFlagsEnabled = mManagerService.addClient(mockClient);
+        boolean enabledAccessibilityEnabled =
+            (stateFlagsEnabled & AccessibilityManager.STATE_FLAG_ACCESSIBILITY_ENABLED) != 0;
+
 
         // check expected result
         assertTrue("The client must be enabled since accessibility is enabled.",
@@ -123,7 +129,9 @@
         MyMockAccessibilityManagerClient mockClient = new MyMockAccessibilityManagerClient();
 
         // invoke the method under test
-        boolean enabledAccessibilityEnabled = mManagerService.addClient(mockClient);
+        final int stateFlagsEnabled = mManagerService.addClient(mockClient);
+        boolean enabledAccessibilityEnabled =
+            (stateFlagsEnabled & AccessibilityManager.STATE_FLAG_ACCESSIBILITY_ENABLED) != 0;
 
         // check expected result
         assertTrue("The client must be enabled since accessibility is enabled.",
@@ -133,7 +141,9 @@
         ensureAccessibilityEnabled(mContext, false);
 
         // invoke the method under test
-        boolean enabledAccessibilityDisabled = mManagerService.addClient(mockClient);
+        final int stateFlagsDisabled = mManagerService.addClient(mockClient);
+        boolean enabledAccessibilityDisabled =
+            (stateFlagsDisabled & AccessibilityManager.STATE_FLAG_ACCESSIBILITY_ENABLED) != 0;
 
         // check expected result
         assertFalse("The client must be disabled since accessibility is disabled.",
@@ -537,10 +547,10 @@
      * This class is a mock {@link IAccessibilityManagerClient}.
      */
     public class MyMockAccessibilityManagerClient extends IAccessibilityManagerClient.Stub {
-        boolean mIsEnabled;
+        int mState;
 
-        public void setEnabled(boolean enabled) {
-            mIsEnabled = enabled;
+        public void setState(int state) {
+            mState = state;
         }
 
         public void setTouchExplorationEnabled(boolean enabled) {
diff --git a/services/tests/servicestests/src/com/android/server/AccessibilityManagerTest.java b/services/tests/servicestests/src/com/android/server/AccessibilityManagerTest.java
index 1463d30..e083815 100644
--- a/services/tests/servicestests/src/com/android/server/AccessibilityManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/AccessibilityManagerTest.java
@@ -70,7 +70,8 @@
 
         // configure the mock service behavior
         IAccessibilityManager mockServiceInterface = mMockServiceInterface;
-        expect(mockServiceInterface.addClient(anyIAccessibilityManagerClient())).andReturn(true);
+        expect(mockServiceInterface.addClient(anyIAccessibilityManagerClient())).andReturn(
+                AccessibilityManager.STATE_FLAG_ACCESSIBILITY_ENABLED);
         expect(mockServiceInterface.getInstalledAccessibilityServiceList()).andReturn(
                 expectedServices);
         replay(mockServiceInterface);
@@ -91,7 +92,8 @@
     public void testInterrupt() throws Exception {
         // configure the mock service behavior
         IAccessibilityManager mockServiceInterface = mMockServiceInterface;
-        expect(mockServiceInterface.addClient(anyIAccessibilityManagerClient())).andReturn(true);
+        expect(mockServiceInterface.addClient(anyIAccessibilityManagerClient())).andReturn(
+                AccessibilityManager.STATE_FLAG_ACCESSIBILITY_ENABLED);
         mockServiceInterface.interrupt();
         replay(mockServiceInterface);
 
@@ -107,7 +109,8 @@
     public void testIsEnabled() throws Exception {
         // configure the mock service behavior
         IAccessibilityManager mockServiceInterface = mMockServiceInterface;
-        expect(mockServiceInterface.addClient(anyIAccessibilityManagerClient())).andReturn(true);
+        expect(mockServiceInterface.addClient(anyIAccessibilityManagerClient())).andReturn(
+                AccessibilityManager.STATE_FLAG_ACCESSIBILITY_ENABLED);
         replay(mockServiceInterface);
 
         // invoke the method under test
@@ -118,7 +121,7 @@
         assertTrue("Must be enabled since the mock service is enabled", isEnabledServiceEnabled);
 
         // disable accessibility
-        manager.getClient().setEnabled(false);
+        manager.getClient().setState(0);
 
         // wait for the asynchronous IBinder call to complete
         Thread.sleep(TIMEOUT_BINDER_CALL);
@@ -141,7 +144,8 @@
 
         // configure the mock service behavior
         IAccessibilityManager mockServiceInterface = mMockServiceInterface;
-        expect(mockServiceInterface.addClient(anyIAccessibilityManagerClient())).andReturn(true);
+        expect(mockServiceInterface.addClient(anyIAccessibilityManagerClient())).andReturn(
+                AccessibilityManager.STATE_FLAG_ACCESSIBILITY_ENABLED);
         expect(mockServiceInterface.sendAccessibilityEvent(eqAccessibilityEvent(sentEvent)))
                 .andReturn(true);
         expect(mockServiceInterface.sendAccessibilityEvent(eqAccessibilityEvent(sentEvent)))
@@ -176,7 +180,7 @@
 
         // configure the mock service behavior
         IAccessibilityManager mockServiceInterface = mMockServiceInterface;
-        expect(mockServiceInterface.addClient(anyIAccessibilityManagerClient())).andReturn(false);
+        expect(mockServiceInterface.addClient(anyIAccessibilityManagerClient())).andReturn(0);
         replay(mockServiceInterface);
 
         // invoke the method under test (accessibility disabled)
diff --git a/wifi/java/android/net/wifi/WifiStateMachine.java b/wifi/java/android/net/wifi/WifiStateMachine.java
index 54685a6..74c6b49 100644
--- a/wifi/java/android/net/wifi/WifiStateMachine.java
+++ b/wifi/java/android/net/wifi/WifiStateMachine.java
@@ -1059,7 +1059,7 @@
         }
     }
 
-    private void startTethering(ArrayList<String> available) {
+    private boolean startTethering(ArrayList<String> available) {
 
         boolean wifiAvailable = false;
 
@@ -1085,18 +1085,20 @@
                     } catch (Exception e) {
                         Log.e(TAG, "Error configuring interface " + intf + ", :" + e);
                         setWifiApEnabled(null, false);
-                        return;
+                        return false;
                     }
 
                     if(mCm.tether(intf) != ConnectivityManager.TETHER_ERROR_NO_ERROR) {
                         Log.e(TAG, "Error tethering on " + intf);
                         setWifiApEnabled(null, false);
-                        return;
+                        return false;
                     }
-                    break;
+                    return true;
                 }
             }
         }
+        // We found no interfaces to tether
+        return false;
     }
 
     private void stopTethering() {
@@ -3098,8 +3100,9 @@
                     break;
                 case CMD_TETHER_INTERFACE:
                     ArrayList<String> available = (ArrayList<String>) message.obj;
-                    startTethering(available);
-                    transitionTo(mTetheredState);
+                    if (startTethering(available)) {
+                        transitionTo(mTetheredState);
+                    }
                     break;
                 case WifiP2pService.P2P_ENABLE_PENDING:
                     // turn of soft Ap and defer to be handled in DriverUnloadedState