Merge "docs: fix a bug in the search results in which clicking a sorting tab does not open that tab until you click a tab again. This occured due to the order of events being out of order in terms of when we invoke the click() on a tab based on the search being invoked. I'm pretty sure this worked fine before, so I think this might have been introduced by a behavior change in CSE. The fix is to simply invoke the click() for a tab when the respective search results actually return using an additional callback."
diff --git a/core/java/android/view/ActionMode.java b/core/java/android/view/ActionMode.java
index e954983..34e7d4d 100644
--- a/core/java/android/view/ActionMode.java
+++ b/core/java/android/view/ActionMode.java
@@ -153,6 +153,18 @@
     public abstract MenuInflater getMenuInflater();
 
     /**
+     * Returns whether the UI presenting this action mode can take focus or not.
+     * This is used by internal components within the framework that would otherwise
+     * present an action mode UI that requires focus, such as an EditText as a custom view.
+     *
+     * @return true if the UI used to show this action mode can take focus
+     * @hide Internal use only
+     */
+    public boolean isUiFocusable() {
+        return true;
+    }
+
+    /**
      * Callback interface for action modes. Supplied to
      * {@link View#startActionMode(Callback)}, a Callback
      * configures and handles events raised by a user's interaction with an action mode.
diff --git a/core/java/android/webkit/FindActionModeCallback.java b/core/java/android/webkit/FindActionModeCallback.java
index a322fa3d..7398262 100644
--- a/core/java/android/webkit/FindActionModeCallback.java
+++ b/core/java/android/webkit/FindActionModeCallback.java
@@ -180,6 +180,14 @@
 
     @Override
     public boolean onCreateActionMode(ActionMode mode, Menu menu) {
+        if (!mode.isUiFocusable()) {
+            // If the action mode we're running in is not focusable the user
+            // will not be able to type into the find on page field. This
+            // should only come up when we're running in a dialog which is
+            // already less than ideal; disable the option for now.
+            return false;
+        }
+
         mode.setCustomView(mCustomView);
         mode.getMenuInflater().inflate(com.android.internal.R.menu.webview_find,
                 menu);
diff --git a/core/java/android/webkit/SelectActionModeCallback.java b/core/java/android/webkit/SelectActionModeCallback.java
index 104deb1..8c174aa 100644
--- a/core/java/android/webkit/SelectActionModeCallback.java
+++ b/core/java/android/webkit/SelectActionModeCallback.java
@@ -17,13 +17,12 @@
 package android.webkit;
 
 import android.app.SearchManager;
+import android.content.Context;
 import android.content.Intent;
 import android.provider.Browser;
-import android.webkit.WebView;
 import android.view.ActionMode;
 import android.view.Menu;
 import android.view.MenuItem;
-import android.view.View;
 
 class SelectActionModeCallback implements ActionMode.Callback {
     private WebView mWebView;
@@ -45,9 +44,25 @@
 
     @Override
     public boolean onCreateActionMode(ActionMode mode, Menu menu) {
-        mode.getMenuInflater().inflate(com.android.internal.R.menu.webview_copy,
-                menu);
-        mode.setTitle(com.android.internal.R.string.textSelectionCABTitle);
+        mode.getMenuInflater().inflate(com.android.internal.R.menu.webview_copy, menu);
+
+        final Context context = mWebView.getContext();
+        boolean allowText = context.getResources().getBoolean(
+                com.android.internal.R.bool.config_allowActionMenuItemTextWithIcon);
+        mode.setTitle(allowText ?
+                context.getString(com.android.internal.R.string.textSelectionCABTitle) : null);
+
+        if (!mode.isUiFocusable()) {
+            // If the action mode UI we're running in isn't capable of taking window focus
+            // the user won't be able to type into the find on page UI. Disable this functionality.
+            // (Note that this should only happen in floating dialog windows.)
+            // This can be removed once we can handle multiple focusable windows at a time
+            // in a better way.
+            final MenuItem findOnPageItem = menu.findItem(com.android.internal.R.id.find);
+            if (findOnPageItem != null) {
+                findOnPageItem.setVisible(false);
+            }
+        }
         mActionMode = mode;
         return true;
     }
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 851c706..eaed9fe 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -4078,8 +4078,8 @@
         boolean pressed = (mTouchMode == TOUCH_SHORTPRESS_START_MODE
                 || mTouchMode == TOUCH_INIT_MODE
                 || mTouchMode == TOUCH_SHORTPRESS_MODE);
-        nativeRecordButtons(hasFocus() && hasWindowFocus(),
-                (pressed && !USE_WEBKIT_RINGS)
+        recordButtons(canvas,
+                hasFocus() && hasWindowFocus(), (pressed && !USE_WEBKIT_RINGS)
                 || mTrackballDown || mGotCenterDown, false);
         drawCoreAndCursorRing(canvas, mBackgroundColor,
                 mDrawCursorRing && drawRings);
@@ -5133,7 +5133,7 @@
                         .obtainMessage(LONG_PRESS_CENTER), LONG_PRESS_TIMEOUT);
                 // Already checked mNativeClass, so we do not need to check it
                 // again.
-                nativeRecordButtons(hasFocus() && hasWindowFocus(), true, true);
+                recordButtons(null, hasFocus() && hasWindowFocus(), true, true);
                 if (!wantsKeyEvents) return true;
             }
             // Bubble up the key event as WebView doesn't handle it
@@ -5561,7 +5561,7 @@
                 mDrawCursorRing = true;
                 setFocusControllerActive(true);
                 if (mNativeClass != 0) {
-                    nativeRecordButtons(true, false, true);
+                    recordButtons(null, true, false, true);
                 }
             } else {
                 if (!inEditingMode()) {
@@ -5570,7 +5570,7 @@
                     mDrawCursorRing = false;
                     setFocusControllerActive(false);
                 }
-                // We do not call nativeRecordButtons here because we assume
+                // We do not call recordButtons here because we assume
                 // that when we lost focus, or window focus, it got called with
                 // false for the first parameter
             }
@@ -5589,7 +5589,7 @@
             mPrivateHandler.removeMessages(SWITCH_TO_LONGPRESS);
             mTouchMode = TOUCH_DONE_MODE;
             if (mNativeClass != 0) {
-                nativeRecordButtons(false, false, true);
+                recordButtons(null, false, false, true);
             }
             setFocusControllerActive(false);
         }
@@ -5647,13 +5647,13 @@
             if (hasWindowFocus()) {
                 mDrawCursorRing = true;
                 if (mNativeClass != 0) {
-                    nativeRecordButtons(true, false, true);
+                    recordButtons(null, true, false, true);
                 }
                 setFocusControllerActive(true);
             //} else {
                 // The WebView has gained focus while we do not have
                 // windowfocus.  When our window lost focus, we should have
-                // called nativeRecordButtons(false...)
+                // called recordButtons(false...)
             }
         } else {
             // When we lost focus, unless focus went to the TextView (which is
@@ -5661,7 +5661,7 @@
             if (!inEditingMode()) {
                 mDrawCursorRing = false;
                 if (mNativeClass != 0) {
-                    nativeRecordButtons(false, false, true);
+                    recordButtons(null, false, false, true);
                 }
                 setFocusControllerActive(false);
             }
@@ -6762,7 +6762,7 @@
             if (mNativeClass == 0) {
                 return false;
             }
-            nativeRecordButtons(hasFocus() && hasWindowFocus(), true, true);
+            recordButtons(null, hasFocus() && hasWindowFocus(), true, true);
             if (time - mLastCursorTime <= TRACKBALL_TIMEOUT
                     && !mLastCursorBounds.equals(nativeGetCursorRingBounds())) {
                 nativeSelectBestAt(mLastCursorBounds);
@@ -9349,6 +9349,24 @@
         return nativeTileProfilingGetFloat(frame, tile, key);
     }
 
+    /**
+     * Helper method to deal with differences between hardware and software rendering
+     */
+    private void recordButtons(Canvas canvas, boolean focus, boolean pressed,
+            boolean inval) {
+        boolean isHardwareAccel = canvas != null
+                ? canvas.isHardwareAccelerated()
+                : isHardwareAccelerated();
+        if (isHardwareAccel) {
+            // We never want to change button state if we are hardware accelerated,
+            // but we DO want to invalidate as necessary so that the GL ring
+            // can be drawn
+            nativeRecordButtons(false, false, inval);
+        } else {
+            nativeRecordButtons(focus, pressed, inval);
+        }
+    }
+
     private native int nativeCacheHitFramePointer();
     private native boolean  nativeCacheHitIsPlugin();
     private native Rect nativeCacheHitNodeBounds();
diff --git a/core/java/android/widget/SpellChecker.java b/core/java/android/widget/SpellChecker.java
index ac9535a..772c129 100644
--- a/core/java/android/widget/SpellChecker.java
+++ b/core/java/android/widget/SpellChecker.java
@@ -30,8 +30,6 @@
 
 import com.android.internal.util.ArrayUtils;
 
-import java.util.Locale;
-
 
 /**
  * Helper class for TextView. Bridge between the TextView and the Dictionnary service.
@@ -167,15 +165,12 @@
 
     @Override
     public void onGetSuggestions(SuggestionsInfo[] results) {
-        final Editable editable = (Editable) mTextView.getText();
         for (int i = 0; i < results.length; i++) {
             SuggestionsInfo suggestionsInfo = results[i];
             if (suggestionsInfo.getCookie() != mCookie) continue;
             final int sequenceNumber = suggestionsInfo.getSequence();
 
             for (int j = 0; j < mLength; j++) {
-                final SpellCheckSpan spellCheckSpan = mSpellCheckSpans[j];
-
                 if (sequenceNumber == mIds[j]) {
                     final int attributes = suggestionsInfo.getSuggestionsAttributes();
                     boolean isInDictionary =
@@ -184,31 +179,78 @@
                             ((attributes & SuggestionsInfo.RESULT_ATTR_LOOKS_LIKE_TYPO) > 0);
 
                     if (!isInDictionary && looksLikeTypo) {
-                        String[] suggestions = getSuggestions(suggestionsInfo);
-                        SuggestionSpan suggestionSpan = new SuggestionSpan(
-                                mTextView.getContext(), suggestions,
-                                SuggestionSpan.FLAG_EASY_CORRECT |
-                                SuggestionSpan.FLAG_MISSPELLED);
-                        final int start = editable.getSpanStart(spellCheckSpan);
-                        final int end = editable.getSpanEnd(spellCheckSpan);
-                        editable.setSpan(suggestionSpan, start, end,
-                                Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
-                        // TODO limit to the word rectangle region
-                        mTextView.invalidate();
+                        createMisspelledSuggestionSpan(suggestionsInfo, mSpellCheckSpans[j]);
                     }
-                    editable.removeSpan(spellCheckSpan);
+                    break;
                 }
             }
         }
     }
 
-    private static String[] getSuggestions(SuggestionsInfo suggestionsInfo) {
-        // A negative suggestion count is possible
-        final int len = Math.max(0, suggestionsInfo.getSuggestionsCount());
-        String[] suggestions = new String[len];
-        for (int j = 0; j < len; j++) {
-            suggestions[j] = suggestionsInfo.getSuggestionAt(j);
+    private void createMisspelledSuggestionSpan(SuggestionsInfo suggestionsInfo,
+            SpellCheckSpan spellCheckSpan) {
+        final Editable editable = (Editable) mTextView.getText();
+        final int start = editable.getSpanStart(spellCheckSpan);
+        final int end = editable.getSpanEnd(spellCheckSpan);
+
+        // Other suggestion spans may exist on that region, with identical suggestions, filter
+        // them out to avoid duplicates. First, filter suggestion spans on that exact region.
+        SuggestionSpan[] suggestionSpans = editable.getSpans(start, end, SuggestionSpan.class);
+        final int length = suggestionSpans.length;
+        for (int i = 0; i < length; i++) {
+            final int spanStart = editable.getSpanStart(suggestionSpans[i]);
+            final int spanEnd = editable.getSpanEnd(suggestionSpans[i]);
+            if (spanStart != start || spanEnd != end) {
+                suggestionSpans[i] = null;
+                break;
+            }
         }
-        return suggestions;
+
+        final int suggestionsCount = suggestionsInfo.getSuggestionsCount();
+        String[] suggestions;
+        if (suggestionsCount <= 0) {
+            // A negative suggestion count is possible
+            suggestions = ArrayUtils.emptyArray(String.class);
+        } else {
+            int numberOfSuggestions = 0;
+            suggestions = new String[suggestionsCount];
+
+            for (int i = 0; i < suggestionsCount; i++) {
+                final String spellSuggestion = suggestionsInfo.getSuggestionAt(i);
+                if (spellSuggestion == null) break;
+                boolean suggestionFound = false;
+
+                for (int j = 0; j < length && !suggestionFound; j++) {
+                    if (suggestionSpans[j] == null) break;
+
+                    String[] suggests = suggestionSpans[j].getSuggestions();
+                    for (int k = 0; k < suggests.length; k++) {
+                        if (spellSuggestion.equals(suggests[k])) {
+                            // The suggestion is already provided by an other SuggestionSpan
+                            suggestionFound = true;
+                            break;
+                        }
+                    }
+                }
+
+                if (!suggestionFound) {
+                    suggestions[numberOfSuggestions++] = spellSuggestion;
+                }
+            }
+
+            if (numberOfSuggestions != suggestionsCount) {
+                String[] newSuggestions = new String[numberOfSuggestions];
+                System.arraycopy(suggestions, 0, newSuggestions, 0, numberOfSuggestions);
+                suggestions = newSuggestions;
+            }
+        }
+
+        SuggestionSpan suggestionSpan = new SuggestionSpan(mTextView.getContext(), suggestions,
+                SuggestionSpan.FLAG_EASY_CORRECT | SuggestionSpan.FLAG_MISSPELLED);
+        editable.setSpan(suggestionSpan, start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
+
+        // TODO limit to the word rectangle region
+        mTextView.invalidate();
+        editable.removeSpan(spellCheckSpan);
     }
 }
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 5cd7902..5edb47c 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -353,6 +353,8 @@
     // Set when this TextView gained focus with some text selected. Will start selection mode.
     private boolean mCreatedWithASelection = false;
 
+    // Size of the window for the word iterator, should be greater than the longest word's length
+    private static final int WORD_ITERATOR_WINDOW_WIDTH = 50;
     private WordIterator mWordIterator;
 
     private SpellChecker mSpellChecker;
@@ -2937,11 +2939,19 @@
 
                 Spannable sp = new SpannableString(mText);
 
-                for (ChangeWatcher cw :
-                     sp.getSpans(0, sp.length(), ChangeWatcher.class)) {
+                for (ChangeWatcher cw : sp.getSpans(0, sp.length(), ChangeWatcher.class)) {
                     sp.removeSpan(cw);
                 }
 
+                SuggestionSpan[] suggestionSpans = sp.getSpans(0, sp.length(), SuggestionSpan.class);
+                for (int i = 0; i < suggestionSpans.length; i++) {
+                    int flags = suggestionSpans[i].getFlags();
+                    if ((flags & SuggestionSpan.FLAG_EASY_CORRECT) != 0
+                            && (flags & SuggestionSpan.FLAG_MISSPELLED) != 0) {
+                        sp.removeSpan(suggestionSpans[i]);
+                    }
+                }
+
                 sp.removeSpan(mSuggestionRangeSpan);
 
                 ss.text = sp;
@@ -4449,7 +4459,6 @@
 
         if (mSpellChecker != null) {
             mSpellChecker.closeSession();
-            removeMisspelledSpans();
             // Forces the creation of a new SpellChecker next time this window is created.
             // Will handle the cases where the settings has been changed in the meantime.
             mSpellChecker = null;
@@ -8461,24 +8470,6 @@
         }
     }
 
-    /**
-     * Removes the suggestion spans for misspelled words.
-     */
-    private void removeMisspelledSpans() {
-        if (mText instanceof Spannable) {
-            Spannable spannable = (Spannable) mText;
-            SuggestionSpan[] suggestionSpans = spannable.getSpans(0,
-                    spannable.length(), SuggestionSpan.class);
-            for (int i = 0; i < suggestionSpans.length; i++) {
-                int flags = suggestionSpans[i].getFlags();
-                if ((flags & SuggestionSpan.FLAG_EASY_CORRECT) != 0
-                        && (flags & SuggestionSpan.FLAG_MISSPELLED) != 0) {
-                    spannable.removeSpan(suggestionSpans[i]);
-                }
-            }
-        }
-    }
-
     @Override
     public boolean onGenericMotionEvent(MotionEvent event) {
         if (mMovement != null && mText instanceof Spannable && mLayout != null) {
@@ -8959,9 +8950,8 @@
             mWordIterator = new WordIterator();
         }
 
-        final int TEXT_WINDOW_WIDTH = 50; // Should be larger than the longest word's length
-        final int windowStart = Math.max(0, start - TEXT_WINDOW_WIDTH);
-        final int windowEnd = Math.min(mText.length(), end + TEXT_WINDOW_WIDTH);
+        final int windowStart = Math.max(0, start - WORD_ITERATOR_WINDOW_WIDTH);
+        final int windowEnd = Math.min(mText.length(), end + WORD_ITERATOR_WINDOW_WIDTH);
         mWordIterator.setCharSequence(mText.subSequence(windowStart, windowEnd));
 
         return windowStart;
@@ -9930,7 +9920,7 @@
                 // Fallback on the default highlight color when the first span does not provide one
                 mSuggestionRangeSpan.setBackgroundColor(mHighlightColor);
             } else {
-                final float BACKGROUND_TRANSPARENCY = 0.3f;
+                final float BACKGROUND_TRANSPARENCY = 0.4f;
                 final int newAlpha = (int) (Color.alpha(underlineColor) * BACKGROUND_TRANSPARENCY);
                 mSuggestionRangeSpan.setBackgroundColor(
                         (underlineColor & 0x00FFFFFF) + (newAlpha << 24));
@@ -9996,7 +9986,9 @@
                 intent.putExtra("word", originalText);
                 intent.setFlags(intent.getFlags() | Intent.FLAG_ACTIVITY_NEW_TASK);
                 getContext().startActivity(intent);
-                suggestionInfo.removeMisspelledFlag();
+                // There is no way to know if the word was indeed added. Re-check.
+                editable.removeSpan(suggestionInfo.suggestionSpan);
+                updateSpellCheckSpans(spanStart, spanEnd);
             } else {
                 // SuggestionSpans are removed by replace: save them before
                 SuggestionSpan[] suggestionSpans = editable.getSpans(spanStart, spanEnd,
diff --git a/core/java/com/android/internal/view/StandaloneActionMode.java b/core/java/com/android/internal/view/StandaloneActionMode.java
index ecda47e..edf4443 100644
--- a/core/java/com/android/internal/view/StandaloneActionMode.java
+++ b/core/java/com/android/internal/view/StandaloneActionMode.java
@@ -36,17 +36,19 @@
     private ActionMode.Callback mCallback;
     private WeakReference<View> mCustomView;
     private boolean mFinished;
+    private boolean mFocusable;
 
     private MenuBuilder mMenu;
 
     public StandaloneActionMode(Context context, ActionBarContextView view,
-            ActionMode.Callback callback) {
+            ActionMode.Callback callback, boolean isFocusable) {
         mContext = context;
         mContextView = view;
         mCallback = callback;
 
         mMenu = new MenuBuilder(context).setDefaultShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
         mMenu.setCallback(this);
+        mFocusable = isFocusable;
     }
 
     @Override
@@ -139,4 +141,8 @@
         invalidate();
         mContextView.showOverflowMenu();
     }
+
+    public boolean isUiFocusable() {
+        return mFocusable;
+    }
 }
diff --git a/core/res/res/layout/screen_simple_overlay_action_mode.xml b/core/res/res/layout/screen_simple_overlay_action_mode.xml
new file mode 100644
index 0000000..eb093e7
--- /dev/null
+++ b/core/res/res/layout/screen_simple_overlay_action_mode.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 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.
+*/
+
+This is an optimized layout for a screen, with the minimum set of features
+enabled.
+-->
+
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:fitsSystemWindows="true">
+    <FrameLayout
+         android:id="@android:id/content"
+         android:layout_width="match_parent"
+         android:layout_height="match_parent"
+         android:foregroundInsidePadding="false"
+         android:foregroundGravity="fill_horizontal|top"
+         android:foreground="?android:attr/windowContentOverlay" />
+    <ViewStub android:id="@+id/action_mode_bar_stub"
+              android:inflatedId="@+id/action_mode_bar"
+              android:layout="@layout/action_mode_bar"
+              android:layout_width="match_parent"
+              android:layout_height="wrap_content" />
+</FrameLayout>
diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml
index b6e213c..13de1c9 100644
--- a/core/res/res/values/styles.xml
+++ b/core/res/res/values/styles.xml
@@ -250,7 +250,7 @@
     </style>
 
     <style name="TextAppearance.EasyCorrectSuggestion" parent="TextAppearance.Suggestion">
-        <item name="android:textUnderlineColor">#ff888888</item>
+        <item name="android:textUnderlineColor">#ffC8C8C8</item>
     </style>
 
     <style name="TextAppearance.MisspelledSuggestion" parent="TextAppearance.Suggestion">
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindow.java b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
index 9205b9a..2cd6eab 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindow.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
@@ -2147,15 +2147,12 @@
                 mActionMode = mode;
             } else {
                 if (mActionModeView == null) {
-                    if (hasFeature(FEATURE_ACTION_MODE_OVERLAY)) {
+                    if (isFloating()) {
                         mActionModeView = new ActionBarContextView(mContext);
                         mActionModePopup = new PopupWindow(mContext, null,
                                 com.android.internal.R.attr.actionModePopupWindowStyle);
                         mActionModePopup.setLayoutInScreenEnabled(true);
                         mActionModePopup.setLayoutInsetDecor(true);
-                        mActionModePopup.setFocusable(true);
-                        mActionModePopup.setOutsideTouchable(false);
-                        mActionModePopup.setTouchModal(false);
                         mActionModePopup.setWindowLayoutType(
                                 WindowManager.LayoutParams.TYPE_APPLICATION);
                         mActionModePopup.setContentView(mActionModeView);
@@ -2186,7 +2183,8 @@
 
                 if (mActionModeView != null) {
                     mActionModeView.killMode();
-                    mode = new StandaloneActionMode(getContext(), mActionModeView, wrappedCallback);
+                    mode = new StandaloneActionMode(getContext(), mActionModeView, wrappedCallback,
+                            mActionModePopup == null);
                     if (callback.onCreateActionMode(mode, mode.getMenu())) {
                         mode.invalidate();
                         mActionModeView.initForMode(mode);
@@ -2664,6 +2662,8 @@
                 layoutResource = com.android.internal.R.layout.screen_title;
             }
             // System.out.println("Title!");
+        } else if ((features & (1 << FEATURE_ACTION_MODE_OVERLAY)) != 0) {
+            layoutResource = com.android.internal.R.layout.screen_simple_overlay_action_mode;
         } else {
             // Embedded, so no decoration is needed.
             layoutResource = com.android.internal.R.layout.screen_simple;
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index 968180c..ed67707 100755
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -276,6 +276,7 @@
     int mLidOpenRotation;
     int mCarDockRotation;
     int mDeskDockRotation;
+    int mHdmiRotation;
 
     int mUserRotationMode = WindowManagerPolicy.USER_ROTATION_FREE;
     int mUserRotation = Surface.ROTATION_0;
@@ -777,6 +778,12 @@
                 ? mContext.getResources().getDimensionPixelSize(
                     com.android.internal.R.dimen.navigation_bar_width)
                 : 0;
+
+        if ("portrait".equals(SystemProperties.get("persist.demo.hdmirotation"))) {
+            mHdmiRotation = mPortraitRotation;
+        } else {
+            mHdmiRotation = mLandscapeRotation;
+        }
     }
 
     public void updateSettings() {
@@ -2922,7 +2929,7 @@
             int preferredRotation = -1;
             if (mHdmiPlugged) {
                 // Ignore sensor when plugged into HDMI.
-                preferredRotation = mLandscapeRotation;
+                preferredRotation = mHdmiRotation;
             } else if (mLidOpen == LID_OPEN && mLidOpenRotation >= 0) {
                 // Ignore sensor when lid switch is open and rotation is forced.
                 preferredRotation = mLidOpenRotation;
diff --git a/services/java/com/android/server/WifiService.java b/services/java/com/android/server/WifiService.java
index 883fc71..660681b 100644
--- a/services/java/com/android/server/WifiService.java
+++ b/services/java/com/android/server/WifiService.java
@@ -149,6 +149,8 @@
     private static final int WIFI_ENABLED                   = 1;
     /* Wifi enabled while in airplane mode */
     private static final int WIFI_ENABLED_AIRPLANE_OVERRIDE = 2;
+    /* Wifi disabled due to airplane mode on */
+    private static final int WIFI_DISABLED_AIRPLANE_ON      = 3;
 
     private AtomicInteger mWifiState = new AtomicInteger(WIFI_DISABLED);
     private AtomicBoolean mAirplaneModeOn = new AtomicBoolean(false);
@@ -478,14 +480,19 @@
 
     private void persistWifiEnabled(boolean enabled) {
         final ContentResolver cr = mContext.getContentResolver();
+        boolean airplane = mAirplaneModeOn.get() && isAirplaneToggleable();
         if (enabled) {
-            if (isAirplaneModeOn() && isAirplaneToggleable()) {
+            if (airplane) {
                 mWifiState.set(WIFI_ENABLED_AIRPLANE_OVERRIDE);
             } else {
                 mWifiState.set(WIFI_ENABLED);
             }
         } else {
-            mWifiState.set(WIFI_DISABLED);
+            if (airplane) {
+                mWifiState.set(WIFI_DISABLED_AIRPLANE_ON);
+            } else {
+                mWifiState.set(WIFI_DISABLED);
+            }
         }
         Settings.Secure.putInt(cr, Settings.Secure.WIFI_ON, mWifiState.get());
     }