Merge "Import revised translations.  DO NOT MERGE" into ics-mr0
diff --git a/Android.mk b/Android.mk
index f41130b..07380bc 100644
--- a/Android.mk
+++ b/Android.mk
@@ -434,8 +434,8 @@
 		            resources/samples/NFCDemo "NFC Demo" \
 		-samplecode $(sample_dir)/NotePad \
 		            resources/samples/NotePad "Note Pad" \
-		-samplecode $(sample_dir)/SampleSpellCheckerService \
-		            resources/samples/SampleSpellCheckerService "Spell Checker" \
+		-samplecode $(sample_dir)/SpellChecker/SampleSpellCheckerService \
+		            resources/samples/SpellChecker/SampleSpellCheckerService "Spell Checker" \
 		-samplecode $(sample_dir)/SampleSyncAdapter \
 		            resources/samples/SampleSyncAdapter "Sample Sync Adapter" \
 		-samplecode $(sample_dir)/RandomMusicPlayer \
diff --git a/core/java/android/accessibilityservice/AccessibilityServiceInfo.java b/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
index 41a3eaca..e5a5e98 100644
--- a/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
+++ b/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
@@ -463,20 +463,34 @@
      * @return The string representation.
      */
     public static String feedbackTypeToString(int feedbackType) {
-        switch (feedbackType) {
-            case FEEDBACK_AUDIBLE:
-                return "FEEDBACK_AUDIBLE";
-            case FEEDBACK_HAPTIC:
-                return "FEEDBACK_HAPTIC";
-            case FEEDBACK_GENERIC:
-                return "FEEDBACK_GENERIC";
-            case FEEDBACK_SPOKEN:
-                return "FEEDBACK_SPOKEN";
-            case FEEDBACK_VISUAL:
-                return "FEEDBACK_VISUAL";
-            default:
-                return null;
+        StringBuilder builder = new StringBuilder();
+        builder.append("[");
+        while (feedbackType > 0) {
+            final int feedbackTypeFlag = 1 << Integer.numberOfTrailingZeros(feedbackType);
+            feedbackType &= ~feedbackTypeFlag;
+            if (builder.length() > 1) {
+                builder.append(", ");
+            }
+            switch (feedbackTypeFlag) {
+                case FEEDBACK_AUDIBLE:
+                    builder.append("FEEDBACK_AUDIBLE");
+                    break;
+                case FEEDBACK_HAPTIC:
+                    builder.append("FEEDBACK_HAPTIC");
+                    break;
+                case FEEDBACK_GENERIC:
+                    builder.append("FEEDBACK_GENERIC");
+                    break;
+                case FEEDBACK_SPOKEN:
+                    builder.append("FEEDBACK_SPOKEN");
+                    break;
+                case FEEDBACK_VISUAL:
+                    builder.append("FEEDBACK_VISUAL");
+                    break;
+            }
         }
+        builder.append("]");
+        return builder.toString();
     }
 
     /**
diff --git a/core/java/android/service/textservice/package.html b/core/java/android/service/textservice/package.html
index 89c6dbc..b498719 100644
--- a/core/java/android/service/textservice/package.html
+++ b/core/java/android/service/textservice/package.html
@@ -32,7 +32,7 @@
 </pre>
 
 <p>For example code, see the <a
-href="{@docRoot}resources/samples/SampleSpellCheckerService/index.html">Spell
+href="{@docRoot}resources/samples/SpellChecker/SampleSpellCheckerService/index.html">Spell
 Checker</a> sample app.</p>
 </BODY>
 </HTML>
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index fe32a5f..93a9d50 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -224,4 +224,9 @@
      * Block until the given window has been drawn to the screen.
      */
     void waitForWindowDrawn(IBinder token, in IRemoteCallback callback);
+
+    /**
+     * Device has a software navigation bar (separate from the status bar).
+     */
+    boolean hasNavigationBar();
 }
diff --git a/core/java/android/view/ViewConfiguration.java b/core/java/android/view/ViewConfiguration.java
index 5e104f9e..3441f7e 100644
--- a/core/java/android/view/ViewConfiguration.java
+++ b/core/java/android/view/ViewConfiguration.java
@@ -292,8 +292,7 @@
         if (!sHasPermanentMenuKeySet) {
             IWindowManager wm = Display.getWindowManager();
             try {
-                sHasPermanentMenuKey = wm.canStatusBarHide() && !res.getBoolean(
-                        com.android.internal.R.bool.config_showNavigationBar);
+                sHasPermanentMenuKey = wm.canStatusBarHide() && !wm.hasNavigationBar();
                 sHasPermanentMenuKeySet = true;
             } catch (RemoteException ex) {
                 sHasPermanentMenuKey = false;
diff --git a/core/java/android/view/WindowManagerPolicy.java b/core/java/android/view/WindowManagerPolicy.java
index 17bdff2..2e19bf6 100644
--- a/core/java/android/view/WindowManagerPolicy.java
+++ b/core/java/android/view/WindowManagerPolicy.java
@@ -1010,6 +1010,11 @@
     public int adjustSystemUiVisibilityLw(int visibility);
 
     /**
+     * Specifies whether there is an on-screen navigation bar separate from the status bar.
+     */
+    public boolean hasNavigationBar();
+
+    /**
      * Print the WindowManagerPolicy's state into the given stream.
      *
      * @param prefix Text to print at the front of each line.
diff --git a/core/java/android/widget/AdapterView.java b/core/java/android/widget/AdapterView.java
index e16a8bd..5d01a0f 100644
--- a/core/java/android/widget/AdapterView.java
+++ b/core/java/android/widget/AdapterView.java
@@ -925,7 +925,7 @@
         event.setCurrentItemIndex(getSelectedItemPosition());
         event.setFromIndex(getFirstVisiblePosition());
         event.setToIndex(getLastVisiblePosition());
-        event.setItemCount(getAdapter().getCount());
+        event.setItemCount(getCount());
     }
 
     private boolean isScrollableForAccessibility() {
diff --git a/core/java/android/widget/DatePicker.java b/core/java/android/widget/DatePicker.java
index 5077be6..0f462ff 100644
--- a/core/java/android/widget/DatePicker.java
+++ b/core/java/android/widget/DatePicker.java
@@ -32,6 +32,7 @@
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityManager;
 import android.view.inputmethod.EditorInfo;
+import android.view.inputmethod.InputMethodManager;
 import android.widget.NumberPicker.OnValueChangeListener;
 
 import com.android.internal.R;
@@ -90,6 +91,12 @@
 
     private final NumberPicker mYearSpinner;
 
+    private final EditText mDaySpinnerInput;
+
+    private final EditText mMonthSpinnerInput;
+
+    private final EditText mYearSpinnerInput;
+
     private final CalendarView mCalendarView;
 
     private Locale mCurrentLocale;
@@ -164,6 +171,7 @@
 
         OnValueChangeListener onChangeListener = new OnValueChangeListener() {
             public void onValueChange(NumberPicker picker, int oldVal, int newVal) {
+                updateInputState();
                 mTempDate.setTimeInMillis(mCurrentDate.getTimeInMillis());
                 // take care of wrapping of days and months to update greater fields
                 if (picker == mDaySpinner) {
@@ -214,6 +222,7 @@
         mDaySpinner.setFormatter(NumberPicker.TWO_DIGIT_FORMATTER);
         mDaySpinner.setOnLongPressUpdateInterval(100);
         mDaySpinner.setOnValueChangedListener(onChangeListener);
+        mDaySpinnerInput = (EditText) mDaySpinner.findViewById(R.id.numberpicker_input);
 
         // month
         mMonthSpinner = (NumberPicker) findViewById(R.id.month);
@@ -222,11 +231,13 @@
         mMonthSpinner.setDisplayedValues(mShortMonths);
         mMonthSpinner.setOnLongPressUpdateInterval(200);
         mMonthSpinner.setOnValueChangedListener(onChangeListener);
+        mMonthSpinnerInput = (EditText) mMonthSpinner.findViewById(R.id.numberpicker_input);
 
         // year
         mYearSpinner = (NumberPicker) findViewById(R.id.year);
         mYearSpinner.setOnLongPressUpdateInterval(100);
         mYearSpinner.setOnValueChangedListener(onChangeListener);
+        mYearSpinnerInput = (EditText) mYearSpinner.findViewById(R.id.numberpicker_input);
 
         // show only what the user required but make sure we
         // show something and the spinners have higher priority
@@ -709,6 +720,27 @@
         mYearSpinner.findViewById(R.id.decrement).setContentDescription(text);
     }
 
+    private void updateInputState() {
+        // Make sure that if the user changes the value and the IME is active
+        // for one of the inputs if this widget, the IME is closed. If the user
+        // changed the value via the IME and there is a next input the IME will
+        // be shown, otherwise the user chose another means of changing the
+        // value and having the IME up makes no sense.
+        InputMethodManager inputMethodManager = InputMethodManager.peekInstance();
+        if (inputMethodManager != null) {
+            if (inputMethodManager.isActive(mYearSpinnerInput)) {
+                mYearSpinnerInput.clearFocus();
+                inputMethodManager.hideSoftInputFromWindow(getWindowToken(), 0);
+            } else if (inputMethodManager.isActive(mMonthSpinnerInput)) {
+                mMonthSpinnerInput.clearFocus();
+                inputMethodManager.hideSoftInputFromWindow(getWindowToken(), 0);
+            } else if (inputMethodManager.isActive(mDaySpinnerInput)) {
+                mDaySpinnerInput.clearFocus();
+                inputMethodManager.hideSoftInputFromWindow(getWindowToken(), 0);
+            }
+        }
+    }
+
     /**
      * Class for managing state storing/restoring.
      */
diff --git a/core/java/android/widget/NumberPicker.java b/core/java/android/widget/NumberPicker.java
index b4c844b..cf015c4 100644
--- a/core/java/android/widget/NumberPicker.java
+++ b/core/java/android/widget/NumberPicker.java
@@ -536,6 +536,10 @@
 
         OnClickListener onClickListener = new OnClickListener() {
             public void onClick(View v) {
+                InputMethodManager inputMethodManager = InputMethodManager.peekInstance();
+                if (inputMethodManager != null && inputMethodManager.isActive(mInputText)) {
+                    inputMethodManager.hideSoftInputFromWindow(getWindowToken(), 0);
+                }
                 mInputText.clearFocus();
                 if (v.getId() == R.id.increment) {
                     changeCurrentByOne(true);
@@ -571,17 +575,14 @@
         mInputText = (EditText) findViewById(R.id.numberpicker_input);
         mInputText.setOnFocusChangeListener(new OnFocusChangeListener() {
             public void onFocusChange(View v, boolean hasFocus) {
-                InputMethodManager inputMethodManager = InputMethodManager.peekInstance();
                 if (hasFocus) {
                     mInputText.selectAll();
+                    InputMethodManager inputMethodManager = InputMethodManager.peekInstance();
                     if (inputMethodManager != null) {
                         inputMethodManager.showSoftInput(mInputText, 0);
                     }
                 } else {
                     mInputText.setSelection(0, 0);
-                    if (inputMethodManager != null) {
-                        inputMethodManager.hideSoftInputFromWindow(getWindowToken(), 0);
-                    }
                     validateInputTextView(v);
                 }
             }
@@ -996,17 +997,14 @@
      * enabled.
      * </p>
      *
-     * @param wrapSelector Whether to wrap.
+     * @param wrapSelectorWheel Whether to wrap.
      */
-    public void setWrapSelectorWheel(boolean wrapSelector) {
-        if (wrapSelector && (mMaxValue - mMinValue) < mSelectorIndices.length) {
+    public void setWrapSelectorWheel(boolean wrapSelectorWheel) {
+        if (wrapSelectorWheel && (mMaxValue - mMinValue) < mSelectorIndices.length) {
             throw new IllegalStateException("Range less than selector items count.");
         }
-        if (wrapSelector != mWrapSelectorWheel) {
-            // force the selector indices array to be reinitialized
-            mSelectorIndices[SELECTOR_MIDDLE_ITEM_INDEX] = Integer.MAX_VALUE;
-            mWrapSelectorWheel = wrapSelector;
-            // force redraw since we might look different
+        if (wrapSelectorWheel != mWrapSelectorWheel) {
+            mWrapSelectorWheel = wrapSelectorWheel;
             updateIncrementAndDecrementButtonsVisibilityState();
         }
     }
@@ -1206,7 +1204,13 @@
         for (int i = 0; i < selectorIndices.length; i++) {
             int selectorIndex = selectorIndices[i];
             String scrollSelectorValue = mSelectorIndexToStringCache.get(selectorIndex);
-            canvas.drawText(scrollSelectorValue, x, y, mSelectorWheelPaint);
+            // Do not draw the middle item if input is visible since the input is shown only
+            // if the wheel is static and it covers the middle item. Otherwise, if the user
+            // starts editing the text via the IME he may see a dimmed version of the old
+            // value intermixed with the new one.
+            if (i != SELECTOR_MIDDLE_ITEM_INDEX || mInputText.getVisibility() != VISIBLE) {
+                canvas.drawText(scrollSelectorValue, x, y, mSelectorWheelPaint);
+            }
             y += mSelectorElementHeight;
         }
 
diff --git a/core/java/android/widget/TimePicker.java b/core/java/android/widget/TimePicker.java
index f52e773..afca2db 100644
--- a/core/java/android/widget/TimePicker.java
+++ b/core/java/android/widget/TimePicker.java
@@ -27,8 +27,8 @@
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.accessibility.AccessibilityEvent;
-import android.view.accessibility.AccessibilityManager;
 import android.view.inputmethod.EditorInfo;
+import android.view.inputmethod.InputMethodManager;
 import android.widget.NumberPicker.OnValueChangeListener;
 
 import com.android.internal.R;
@@ -79,6 +79,12 @@
 
     private final NumberPicker mAmPmSpinner;
 
+    private final EditText mHourSpinnerInput;
+
+    private final EditText mMinuteSpinnerInput;
+
+    private final EditText mAmPmSpinnerInput;
+
     private final TextView mDivider;
 
     // Note that the legacy implementation of the TimePicker is
@@ -140,6 +146,7 @@
         mHourSpinner = (NumberPicker) findViewById(R.id.hour);
         mHourSpinner.setOnValueChangedListener(new NumberPicker.OnValueChangeListener() {
             public void onValueChange(NumberPicker spinner, int oldVal, int newVal) {
+                updateInputState();
                 if (!is24HourView()) {
                     if ((oldVal == HOURS_IN_HALF_DAY - 1 && newVal == HOURS_IN_HALF_DAY)
                             || (oldVal == HOURS_IN_HALF_DAY && newVal == HOURS_IN_HALF_DAY - 1)) {
@@ -150,8 +157,8 @@
                 onTimeChanged();
             }
         });
-        EditText hourInput = (EditText) mHourSpinner.findViewById(R.id.numberpicker_input);
-        hourInput.setImeOptions(EditorInfo.IME_ACTION_NEXT);
+        mHourSpinnerInput = (EditText) mHourSpinner.findViewById(R.id.numberpicker_input);
+        mHourSpinnerInput.setImeOptions(EditorInfo.IME_ACTION_NEXT);
 
         // divider (only for the new widget style)
         mDivider = (TextView) findViewById(R.id.divider);
@@ -167,6 +174,7 @@
         mMinuteSpinner.setFormatter(NumberPicker.TWO_DIGIT_FORMATTER);
         mMinuteSpinner.setOnValueChangedListener(new NumberPicker.OnValueChangeListener() {
             public void onValueChange(NumberPicker spinner, int oldVal, int newVal) {
+                updateInputState();
                 int minValue = mMinuteSpinner.getMinValue();
                 int maxValue = mMinuteSpinner.getMaxValue();
                 if (oldVal == maxValue && newVal == minValue) {
@@ -187,8 +195,8 @@
                 onTimeChanged();
             }
         });
-        EditText minuteInput = (EditText) mMinuteSpinner.findViewById(R.id.numberpicker_input);
-        minuteInput.setImeOptions(EditorInfo.IME_ACTION_NEXT);
+        mMinuteSpinnerInput = (EditText) mMinuteSpinner.findViewById(R.id.numberpicker_input);
+        mMinuteSpinnerInput.setImeOptions(EditorInfo.IME_ACTION_NEXT);
 
         /* Get the localized am/pm strings and use them in the spinner */
         mAmPmStrings = new DateFormatSymbols().getAmPmStrings();
@@ -197,6 +205,7 @@
         View amPmView = findViewById(R.id.amPm);
         if (amPmView instanceof Button) {
             mAmPmSpinner = null;
+            mAmPmSpinnerInput = null;
             mAmPmButton = (Button) amPmView;
             mAmPmButton.setOnClickListener(new OnClickListener() {
                 public void onClick(View button) {
@@ -213,13 +222,14 @@
             mAmPmSpinner.setDisplayedValues(mAmPmStrings);
             mAmPmSpinner.setOnValueChangedListener(new OnValueChangeListener() {
                 public void onValueChange(NumberPicker picker, int oldVal, int newVal) {
+                    updateInputState();
                     picker.requestFocus();
                     mIsAm = !mIsAm;
                     updateAmPmControl();
                 }
             });
-            EditText amPmInput = (EditText) mAmPmSpinner.findViewById(R.id.numberpicker_input);
-            amPmInput.setImeOptions(EditorInfo.IME_ACTION_DONE);
+            mAmPmSpinnerInput = (EditText) mAmPmSpinner.findViewById(R.id.numberpicker_input);
+            mAmPmSpinnerInput.setImeOptions(EditorInfo.IME_ACTION_DONE);
         }
 
         // update controls to initial state
@@ -319,7 +329,7 @@
             dest.writeInt(mMinute);
         }
 
-        @SuppressWarnings("unused")
+        @SuppressWarnings({"unused", "hiding"})
         public static final Parcelable.Creator<SavedState> CREATOR = new Creator<SavedState>() {
             public SavedState createFromParcel(Parcel in) {
                 return new SavedState(in);
@@ -524,4 +534,25 @@
             mAmPmSpinner.findViewById(R.id.decrement).setContentDescription(text);
         }
     }
+
+    private void updateInputState() {
+        // Make sure that if the user changes the value and the IME is active
+        // for one of the inputs if this widget, the IME is closed. If the user
+        // changed the value via the IME and there is a next input the IME will
+        // be shown, otherwise the user chose another means of changing the
+        // value and having the IME up makes no sense.
+        InputMethodManager inputMethodManager = InputMethodManager.peekInstance();
+        if (inputMethodManager != null) {
+            if (inputMethodManager.isActive(mHourSpinnerInput)) {
+                mHourSpinnerInput.clearFocus();
+                inputMethodManager.hideSoftInputFromWindow(getWindowToken(), 0);
+            } else if (inputMethodManager.isActive(mMinuteSpinnerInput)) {
+                mMinuteSpinnerInput.clearFocus();
+                inputMethodManager.hideSoftInputFromWindow(getWindowToken(), 0);
+            } else if (inputMethodManager.isActive(mAmPmSpinnerInput)) {
+                mAmPmSpinnerInput.clearFocus();
+                inputMethodManager.hideSoftInputFromWindow(getWindowToken(), 0);
+            }
+        }
+    }
 }
diff --git a/core/java/com/android/internal/widget/TransportControlView.java b/core/java/com/android/internal/widget/TransportControlView.java
index 63a3aa5..979eb81 100644
--- a/core/java/com/android/internal/widget/TransportControlView.java
+++ b/core/java/com/android/internal/widget/TransportControlView.java
@@ -86,11 +86,6 @@
      */
     private Bundle mPopulateMetadataWhenAttached = null;
 
-    /**
-     * Whether to clear the interface next time it is shown (i.e. the generation id changed)
-     */
-    private boolean mClearOnNextShow;
-
     // This handler is required to ensure messages from IRCD are handled in sequence and on
     // the UI thread.
     private Handler mHandler = new Handler() {
@@ -121,7 +116,10 @@
 
             case MSG_SET_GENERATION_ID:
                 if (msg.arg2 != 0) {
-                    mClearOnNextShow = true; // TODO: handle this
+                    // This means nobody is currently registered. Hide the view.
+                    if (mWidgetCallbacks != null) {
+                        mWidgetCallbacks.requestHide(TransportControlView.this);
+                    }
                 }
                 if (DEBUG) Log.v(TAG, "New genId = " + msg.arg1 + ", clearing = " + msg.arg2);
                 mClientGeneration = msg.arg1;
@@ -412,7 +410,7 @@
         if (DEBUG) Log.v(TAG, "onSaveInstanceState()");
         Parcelable superState = super.onSaveInstanceState();
         SavedState ss = new SavedState(superState);
-        ss.wasShowing = mWidgetCallbacks.isVisible(this);
+        ss.wasShowing = mWidgetCallbacks != null && mWidgetCallbacks.isVisible(this);
         return ss;
     }
 
@@ -425,7 +423,7 @@
         }
         SavedState ss = (SavedState) state;
         super.onRestoreInstanceState(ss.getSuperState());
-        if (ss.wasShowing) {
+        if (ss.wasShowing && mWidgetCallbacks != null) {
             mWidgetCallbacks.requestShow(this);
         }
     }
@@ -449,6 +447,11 @@
     }
 
     private void sendMediaButtonClick(int keyCode) {
+        if (mClientIntent == null) {
+            // Shouldn't be possible because this view should be hidden in this case.
+            Log.e(TAG, "sendMediaButtonClick(): No client is currently registered");
+            return;
+        }
         // use the registered PendingIntent that will be processed by the registered
         //    media button event receiver, which is the component of mClientIntent
         KeyEvent keyEvent = new KeyEvent(KeyEvent.ACTION_DOWN, keyCode);
diff --git a/data/sounds/effects/ogg/KeypressDelete_120.ogg b/data/sounds/effects/ogg/KeypressDelete_120.ogg
new file mode 100644
index 0000000..f2851f7
--- /dev/null
+++ b/data/sounds/effects/ogg/KeypressDelete_120.ogg
Binary files differ
diff --git a/data/sounds/effects/ogg/KeypressReturn_120.ogg b/data/sounds/effects/ogg/KeypressReturn_120.ogg
new file mode 100644
index 0000000..48a26b4
--- /dev/null
+++ b/data/sounds/effects/ogg/KeypressReturn_120.ogg
Binary files differ
diff --git a/data/sounds/effects/ogg/KeypressSpacebar_120.ogg b/data/sounds/effects/ogg/KeypressSpacebar_120.ogg
new file mode 100644
index 0000000..9620927
--- /dev/null
+++ b/data/sounds/effects/ogg/KeypressSpacebar_120.ogg
Binary files differ
diff --git a/data/sounds/effects/ogg/KeypressStandard_120.ogg b/data/sounds/effects/ogg/KeypressStandard_120.ogg
new file mode 100644
index 0000000..e4d916a
--- /dev/null
+++ b/data/sounds/effects/ogg/KeypressStandard_120.ogg
Binary files differ
diff --git a/docs/html/resources/resources-data.js b/docs/html/resources/resources-data.js
index 310310e..38357ef 100644
--- a/docs/html/resources/resources-data.js
+++ b/docs/html/resources/resources-data.js
@@ -599,7 +599,7 @@
   },
   {
     tags: ['sample', 'input', 'new'],
-    path: 'samples/SampleSpellCheckerService/index.html',
+    path: 'samples/SpellChecker/SampleSpellCheckerService/index.html',
     title: {
       en: 'Spell Checker'
     },
diff --git a/docs/html/sdk/android-4.0-highlights.jd b/docs/html/sdk/android-4.0-highlights.jd
index fe69e12..467159b 100644
--- a/docs/html/sdk/android-4.0-highlights.jd
+++ b/docs/html/sdk/android-4.0-highlights.jd
@@ -14,7 +14,6 @@
 }
 #jd-content div.video {
   float:right;
-  padding:0 60px 40px;
   margin-top:-15px;
 }
 #jd-content table.columns {
@@ -37,18 +36,12 @@
   font-weight:bold;
 }
 </style>
-<!--
-<div class="video" style="border:1px solid gray;width:250px;height:180px;margin:1.5em">
-<object width="278" height="180">
-<xparam name="movie" value="http://www.youtube.com/v/Jx3pdWBlZ34?hl=en&fs=1"></param>
-<xparam name="allowFullScreen" value="true"></param><param name="allowscriptaccess"
-value="always"></param>
-ICS CONSUMER VIDEO [ziwang]
-<embed xsrc="http://www.youtube.com/v/Jx3pdWBlZ34?hl=en&fs=1" type="application/x-shockwave-flash"
-allowscriptaccess="always" allowfullscreen="true" width="278" height="180"></embed>
-</object>
+
+<div class="video" style="margin:1.5em 0 1.5em 1.5em">
+<iframe width="380" height="223" src="http://www.youtube.com/embed/-F_ke3rxopc?hd=1" frameborder="0"
+allowfullscreen></iframe>
 </div>
--->
+
 <p>Welcome to Android 4.0!</p>
 
 <p>Android 4.0 delivers a refined, unified UI for phones and tablets and introduces innovative features for users and developers. This document provides a glimpse of the many new features and technologies that make Android 4.0 simple, beautiful, and beyond smart. <!--For technical details about
@@ -178,9 +171,9 @@
 <p style="margin-top:1em;margin-bottom:.75em;"><strong>Swipe to dismiss
 notifications, tasks, and browser tabs</strong></p>
 
-<p>Android 4.0 makes managing notifications, recent apps, and browoser tabs even
+<p>Android 4.0 makes managing notifications, recent apps, and brwoser tabs even
 easier. Users can now dismiss individual notifications, apps from the Recent
-Apps list, and browser tabs lists with a simple swipe of a finger. </p>
+Apps list, and browser tabs with a simple swipe of a finger. </p>
 
 <div  style="padding-top:0em;">
 <div style="margin-right:1em;float:right;margin-left:1em;margin-top:1.5em;margin-bottom:0;padding-bottom:0;width:200px">
@@ -300,15 +293,15 @@
 linked together and integrated for easy accessibility. At the center is a new
 <strong>People app</strong> that offers richer profile information, including a
 large profile picture, phone numbers, addresses and accounts, status updates,
-and a new button for connecting on integrated social networks. </p>
+events, and a new button for connecting on integrated social networks. </p>
 
 <p>The user's own contact information is stored in a new <strong>"Me"
 profile</strong>, allowing easier sharing with apps and people. All of the
 user's integrated contacts are displayed in an easy to manage list, including
 controls over which contacts are shown from any integrated account or social
 network. Wherever the user navigates across the system, tapping a profile photo
-displays Quick Contacts, with shortcuts to phone numbers, text messaging, and
-more. </p>
+displays Quick Contacts, with large profile pictures, shortcuts to phone numbers,
+text messaging, and more. </p>
 
 
 <p style="margin-top:1em;margin-bottom:.75em;"><strong>Unified calendar, visual
@@ -343,7 +336,7 @@
 <p style="margin-top:1em;margin-bottom:.75em;"><strong>Rich and versatile camera
 capabilities</strong></p>
 
-<p>The Camera app includes many new features let users capture special moments
+<p>The Camera app includes many new features that let users capture special moments
 with great photos and videos. After capturing images, they can edit and share
 them easily with friemds. </p>
 
@@ -405,7 +398,15 @@
 
 <p style="margin-top:1em;margin-bottom:.75em;"><strong>Live Effects for transforming video</strong></p>
 
-<p>Live Effects is a collection of graphical transformations that add interest and fun to videos captured in the Camera app. For example, users can change the background behind them to any stock or custom image, for just the right setting when shooting video or using Google Talk video chat. Also available is Silly Faces, a set of morphing effects that use state-of-the-art face recognition and GPU filters to add great effects facial features during video capture. For example, you can use effects such as small eyes, big mouth, big nose, face squeeze, and more. Outside of the Camera app, Live Effects is available during video chat in the Google Talk app.</p>
+<p>Live Effects is a collection of graphical transformations that add interest
+and fun to videos captured in the Camera app. For example, users can change the
+background behind them to any stock or custom image, for just the right setting
+when shooting video or using Google Talk video chat. Also available is Silly
+Faces, a set of morphing effects that use state-of-the-art face recognition and
+GPU filters to add great effects to facial features during video capture. For
+example, you can use effects such as small eyes, big mouth, big nose, face
+squeeze, and more. Outside of the Camera app, Live Effects is available during
+video chat in the Google Talk app.</p>
 
 <div  style="padding-top:0em;">
 <div style="margsin-right:.8em;float:left;width:186px;padding-top:1em;">
@@ -418,7 +419,10 @@
 
 <p style="margin-top:1em;margin-bottom:.75em;"><strong>Sharing with screenshots</strong></p>
 
-<p>Users can now share what's on their screens more easily by taking screenshots. Hardware buttons let them snap a <strong>screenshot</strong> and store it locally. Afterward, they can view, edit, and share the screen shot in Gallery or a similar app.</p>
+<p>Users can now share what's on their screens more easily by taking
+screenshots. Hardware buttons let them snap a <strong>screenshot</strong> and
+store it locally. Afterward, they can view, edit, and share the screen shot in
+Gallery or a similar app.</p>
 
 
 <h3 id="cloud" style="color:#172861">Cloud-connected experience</h3>
@@ -435,14 +439,18 @@
 </div>
 </div>
 
-<p>Android has always been cloud-connected, letting users browse the web and sync photos, apps, games, email, and contacts &mdash; wherever they are and across all of their devices. Android 4.0 adds new browsing and email capabilities to let users take even more with them and keep communication organized.</p>
+<p>Android has always been cloud-connected, letting users browse the web and
+sync photos, apps, games, email, and contacts &mdash; wherever they are and
+across all of their devices. Android 4.0 adds new browsing and email
+capabilities to let users take even more with them and keep communication
+organized.</p>
 
 
 <p style="margin-top:1em;margin-bottom:.75em;"><strong>Powerful web
 browsing</strong></p>
 
 <p>The Android Browser offers an experience that’s as rich and convenient as a
-desktop browser. It lets users instantly and manage <strong>sync Google Chrome
+desktop browser. It lets users instantly sync and manage <strong>Google Chrome
 bookmarks</strong> from all of their accounts, jump to their favorite content
 faster, and even save it for reading later in case there's no network
 available.</p>
@@ -641,7 +649,7 @@
 
 <p>Applications can also let users set up a social connection to a contact from
 the People app. When the user touches Add Connection in a contact, the app
-broadcasts a public intent that other apps can handle, displaying any UI needed
+sends a public intent that other apps can handle, displaying any UI needed
 to create the social connection.</p>
 
 <p>Building on the social API, developers can add powerful new interactions that
@@ -659,7 +667,7 @@
 and handle the display of event alerts and reminders. Using the calendar
 provider, applications can take advantage of event data sourced from a variety
 of apps and protocols, to offer innovative ways of viewing and managing a user’s
-events. Apps can also use of calendar data to improve the relevance of their
+events. Apps can also use calendar data to improve the relevance of their
 other content.</p>
 
 <p>For lighter-weight access to calendar services, the Calendar app defines a
diff --git a/docs/html/sdk/android-4.0.jd b/docs/html/sdk/android-4.0.jd
index 90319878..68f9507 100644
--- a/docs/html/sdk/android-4.0.jd
+++ b/docs/html/sdk/android-4.0.jd
@@ -957,8 +957,8 @@
 include a {@code &lt;meta-data&gt;} element that declares configuration information for the spell
 checker. </p>
 
-<p>See the <a href="{@docRoot}resources/samples/SampleSpellCheckerService/index.html">Spell
-Checker</a> sample app for example code.</p>
+<p>See the <a href="{@docRoot}resources/samples/SpellChecker/SampleSpellCheckerService/index.html">
+Spell Checker</a> sample app for example code.</p>
 
 
 
diff --git a/docs/html/sdk/images/4.0/lock-camera-lg.png b/docs/html/sdk/images/4.0/lock-camera-lg.png
index 2a169b3..c82cec6 100644
--- a/docs/html/sdk/images/4.0/lock-camera-lg.png
+++ b/docs/html/sdk/images/4.0/lock-camera-lg.png
Binary files differ
diff --git a/docs/html/sdk/images/4.0/lock-camera.png b/docs/html/sdk/images/4.0/lock-camera.png
index a5c63c3..d3cc153 100644
--- a/docs/html/sdk/images/4.0/lock-camera.png
+++ b/docs/html/sdk/images/4.0/lock-camera.png
Binary files differ
diff --git a/include/media/IOMX.h b/include/media/IOMX.h
index 02ad703..c4cc947 100644
--- a/include/media/IOMX.h
+++ b/include/media/IOMX.h
@@ -78,6 +78,9 @@
             node_id node, OMX_INDEXTYPE index,
             const void *params, size_t size) = 0;
 
+    virtual status_t getState(
+            node_id node, OMX_STATETYPE* state) = 0;
+
     virtual status_t storeMetaDataInBuffers(
             node_id node, OMX_U32 port_index, OMX_BOOL enable) = 0;
 
diff --git a/media/libmedia/IOMX.cpp b/media/libmedia/IOMX.cpp
index d3aab08..7d2fbce 100644
--- a/media/libmedia/IOMX.cpp
+++ b/media/libmedia/IOMX.cpp
@@ -38,6 +38,7 @@
     SET_PARAMETER,
     GET_CONFIG,
     SET_CONFIG,
+    GET_STATE,
     ENABLE_GRAPHIC_BUFFERS,
     USE_BUFFER,
     USE_GRAPHIC_BUFFER,
@@ -198,6 +199,17 @@
         return reply.readInt32();
     }
 
+    virtual status_t getState(
+            node_id node, OMX_STATETYPE* state) {
+        Parcel data, reply;
+        data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
+        data.writeIntPtr((intptr_t)node);
+        remote()->transact(GET_STATE, data, &reply);
+
+        *state = static_cast<OMX_STATETYPE>(reply.readInt32());
+        return reply.readInt32();
+    }
+
     virtual status_t enableGraphicBuffers(
             node_id node, OMX_U32 port_index, OMX_BOOL enable) {
         Parcel data, reply;
@@ -524,6 +536,20 @@
             return NO_ERROR;
         }
 
+        case GET_STATE:
+        {
+            CHECK_INTERFACE(IOMX, data, reply);
+
+            node_id node = (void*)data.readIntPtr();
+            OMX_STATETYPE state = OMX_StateInvalid;
+
+            status_t err = getState(node, &state);
+            reply->writeInt32(state);
+            reply->writeInt32(err);
+
+            return NO_ERROR;
+        }
+
         case ENABLE_GRAPHIC_BUFFERS:
         {
             CHECK_INTERFACE(IOMX, data, reply);
diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp
index b5eef94..3ebe989 100644
--- a/media/libmediaplayerservice/MediaPlayerService.cpp
+++ b/media/libmediaplayerservice/MediaPlayerService.cpp
@@ -374,11 +374,13 @@
         } else {
             for (int i = 0, n = mMediaRecorderClients.size(); i < n; ++i) {
                 sp<MediaRecorderClient> c = mMediaRecorderClients[i].promote();
-                snprintf(buffer, 255, " MediaRecorderClient pid(%d)\n", c->mPid);
-                result.append(buffer);
-                write(fd, result.string(), result.size());
-                result = "\n";
-                c->dump(fd, args);
+                if (c != 0) {
+                    snprintf(buffer, 255, " MediaRecorderClient pid(%d)\n", c->mPid);
+                    result.append(buffer);
+                    write(fd, result.string(), result.size());
+                    result = "\n";
+                    c->dump(fd, args);
+                }
             }
         }
 
diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp
index 7b7078a..00d414c 100755
--- a/media/libstagefright/OMXCodec.cpp
+++ b/media/libstagefright/OMXCodec.cpp
@@ -3609,11 +3609,24 @@
         mAsyncCompletion.wait(mLock);
     }
 
+    bool isError = false;
     switch (mState) {
         case LOADED:
-        case ERROR:
             break;
 
+        case ERROR:
+        {
+            OMX_STATETYPE state = OMX_StateInvalid;
+            status_t err = mOMX->getState(mNode, &state);
+            CHECK_EQ(err, (status_t)OK);
+
+            if (state != OMX_StateExecuting) {
+                break;
+            }
+            // else fall through to the idling code
+            isError = true;
+        }
+
         case EXECUTING:
         {
             setState(EXECUTING_TO_IDLE);
@@ -3648,6 +3661,12 @@
                 mAsyncCompletion.wait(mLock);
             }
 
+            if (isError) {
+                // We were in the ERROR state coming in, so restore that now
+                // that we've idled the OMX component.
+                setState(ERROR);
+            }
+
             break;
         }
 
diff --git a/media/libstagefright/include/OMX.h b/media/libstagefright/include/OMX.h
index d54b1c1..53e764f 100644
--- a/media/libstagefright/include/OMX.h
+++ b/media/libstagefright/include/OMX.h
@@ -59,6 +59,9 @@
             node_id node, OMX_INDEXTYPE index,
             const void *params, size_t size);
 
+    virtual status_t getState(
+            node_id node, OMX_STATETYPE* state);
+
     virtual status_t enableGraphicBuffers(
             node_id node, OMX_U32 port_index, OMX_BOOL enable);
 
diff --git a/media/libstagefright/include/OMXNodeInstance.h b/media/libstagefright/include/OMXNodeInstance.h
index 1ccf50d..47ca579 100644
--- a/media/libstagefright/include/OMXNodeInstance.h
+++ b/media/libstagefright/include/OMXNodeInstance.h
@@ -49,6 +49,8 @@
     status_t getConfig(OMX_INDEXTYPE index, void *params, size_t size);
     status_t setConfig(OMX_INDEXTYPE index, const void *params, size_t size);
 
+    status_t getState(OMX_STATETYPE* state);
+
     status_t enableGraphicBuffers(OMX_U32 portIndex, OMX_BOOL enable);
 
     status_t getGraphicBufferUsage(OMX_U32 portIndex, OMX_U32* usage);
diff --git a/media/libstagefright/omx/OMX.cpp b/media/libstagefright/omx/OMX.cpp
index 33d3f30..3715fe9 100644
--- a/media/libstagefright/omx/OMX.cpp
+++ b/media/libstagefright/omx/OMX.cpp
@@ -303,6 +303,12 @@
             index, params, size);
 }
 
+status_t OMX::getState(
+        node_id node, OMX_STATETYPE* state) {
+    return findInstance(node)->getState(
+            state);
+}
+
 status_t OMX::enableGraphicBuffers(
         node_id node, OMX_U32 port_index, OMX_BOOL enable) {
     return findInstance(node)->enableGraphicBuffers(port_index, enable);
diff --git a/media/libstagefright/omx/OMXNodeInstance.cpp b/media/libstagefright/omx/OMXNodeInstance.cpp
index b612f89..0ff398a 100644
--- a/media/libstagefright/omx/OMXNodeInstance.cpp
+++ b/media/libstagefright/omx/OMXNodeInstance.cpp
@@ -266,6 +266,14 @@
     return StatusFromOMXError(err);
 }
 
+status_t OMXNodeInstance::getState(OMX_STATETYPE* state) {
+    Mutex::Autolock autoLock(mLock);
+
+    OMX_ERRORTYPE err = OMX_GetState(mHandle, state);
+
+    return StatusFromOMXError(err);
+}
+
 status_t OMXNodeInstance::enableGraphicBuffers(
         OMX_U32 portIndex, OMX_BOOL enable) {
     Mutex::Autolock autoLock(mLock);
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_notify_image.png b/packages/SystemUI/res/drawable-hdpi/stat_notify_image.png
new file mode 100644
index 0000000..319f925
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_notify_image.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_notify_image_error.png b/packages/SystemUI/res/drawable-hdpi/stat_notify_image_error.png
new file mode 100644
index 0000000..fa8d4bf
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_notify_image_error.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_notify_image.png b/packages/SystemUI/res/drawable-mdpi/stat_notify_image.png
new file mode 100644
index 0000000..5036e8d
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_notify_image.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_notify_image_error.png b/packages/SystemUI/res/drawable-mdpi/stat_notify_image_error.png
new file mode 100644
index 0000000..94487bf
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_notify_image_error.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_notify_image.png b/packages/SystemUI/res/drawable-xhdpi/stat_notify_image.png
new file mode 100644
index 0000000..3c5c082
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_notify_image.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_notify_image_error.png b/packages/SystemUI/res/drawable-xhdpi/stat_notify_image_error.png
new file mode 100644
index 0000000..8aa19e4
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_notify_image_error.png
Binary files differ
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
index 301ae73..cc1b8ed 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
@@ -137,7 +137,7 @@
                     + (mTickerAddSpace ? " " : ""))
             .setContentTitle(r.getString(R.string.screenshot_saving_title))
             .setContentText(r.getString(R.string.screenshot_saving_text))
-            .setSmallIcon(android.R.drawable.ic_menu_gallery)
+            .setSmallIcon(R.drawable.stat_notify_image)
             .setWhen(System.currentTimeMillis());
         Notification n = mNotificationBuilder.getNotification();
         n.flags |= Notification.FLAG_NO_CLEAR;
@@ -544,7 +544,7 @@
             .setTicker(r.getString(R.string.screenshot_failed_title))
             .setContentTitle(r.getString(R.string.screenshot_failed_title))
             .setContentText(r.getString(R.string.screenshot_failed_text))
-            .setSmallIcon(android.R.drawable.ic_menu_report_image)
+            .setSmallIcon(R.drawable.stat_notify_image_error)
             .setWhen(System.currentTimeMillis())
             .setAutoCancel(true)
             .getNotification();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index 352d4a1..87e505b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -297,15 +297,15 @@
         mStatusBarView = sb;
 
         try {
-            boolean showNav = res.getBoolean(com.android.internal.R.bool.config_showNavigationBar);
+            boolean showNav = mWindowManager.hasNavigationBar();
             if (showNav) {
                 mNavigationBarView = 
                     (NavigationBarView) View.inflate(context, R.layout.navigation_bar, null);
 
                 mNavigationBarView.setDisabledFlags(mDisabled);
             }
-        } catch (Resources.NotFoundException ex) {
-            // no nav bar for you
+        } catch (RemoteException ex) {
+            // no window manager? good luck with that
         }
 
         // figure out which pixel-format to use for the status bar.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
index 4f9eb38..1d4b9ba 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
@@ -95,7 +95,7 @@
     final WifiManager mWifiManager;
     AsyncChannel mWifiChannel;
     boolean mWifiEnabled, mWifiConnected;
-    int mWifiLevel;
+    int mWifiRssi, mWifiLevel;
     String mWifiSsid;
     int mWifiIconId = 0;
     int mWifiActivityIconId = 0; // overlay arrows for wifi direction
@@ -654,24 +654,29 @@
             mWifiConnected = networkInfo != null && networkInfo.isConnected();
             // If we just connected, grab the inintial signal strength and ssid
             if (mWifiConnected && !wasConnected) {
-                WifiInfo info = mWifiManager.getConnectionInfo();
+                // try getting it out of the intent first
+                WifiInfo info = (WifiInfo) intent.getParcelableExtra(WifiManager.EXTRA_WIFI_INFO);
+                if (info == null) {
+                    info = mWifiManager.getConnectionInfo();
+                }
                 if (info != null) {
-                    mWifiLevel = WifiManager.calculateSignalLevel(info.getRssi(),
-                            WifiIcons.WIFI_LEVEL_COUNT);
                     mWifiSsid = huntForSsid(info);
                 } else {
-                    mWifiLevel = 0;
                     mWifiSsid = null;
                 }
             } else if (!mWifiConnected) {
-                mWifiLevel = 0;
                 mWifiSsid = null;
             }
-
+            // Apparently the wifi level is not stable at this point even if we've just connected to
+            // the network; we need to wait for an RSSI_CHANGED_ACTION for that. So let's just set
+            // it to 0 for now
+            mWifiLevel = 0;
+            mWifiRssi = -200;
         } else if (action.equals(WifiManager.RSSI_CHANGED_ACTION)) {
             if (mWifiConnected) {
-                final int newRssi = intent.getIntExtra(WifiManager.EXTRA_NEW_RSSI, -200);
-                mWifiLevel = WifiManager.calculateSignalLevel(newRssi, WifiIcons.WIFI_LEVEL_COUNT);
+                mWifiRssi = intent.getIntExtra(WifiManager.EXTRA_NEW_RSSI, -200);
+                mWifiLevel = WifiManager.calculateSignalLevel(
+                        mWifiRssi, WifiIcons.WIFI_LEVEL_COUNT);
             }
         }
 
@@ -1031,6 +1036,8 @@
         pw.println(mWifiEnabled);
         pw.print("  mWifiConnected=");
         pw.println(mWifiConnected);
+        pw.print("  mWifiRssi=");
+        pw.println(mWifiRssi);
         pw.print("  mWifiLevel=");
         pw.println(mWifiLevel);
         pw.print("  mWifiSsid=");
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java
index de8226b..00bdd44 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java
@@ -444,11 +444,14 @@
 
         sb.setHandler(mHandler);
 
-        // Sanity-check that someone hasn't set up the config wrong and asked for a navigation bar
-        // on a tablet that has only the system bar
-        if (mContext.getResources().getBoolean(
-                com.android.internal.R.bool.config_showNavigationBar)) {
-            throw new RuntimeException("Tablet device cannot show navigation bar and system bar");
+        try {
+            // Sanity-check that someone hasn't set up the config wrong and asked for a navigation
+            // bar on a tablet that has only the system bar
+            if (mWindowManager.hasNavigationBar()) {
+                throw new RuntimeException(
+                        "Tablet device cannot show navigation bar and system bar");
+            }
+        } catch (RemoteException ex) {
         }
 
         mBarContents = (ViewGroup) sb.findViewById(R.id.bar_contents);
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index b9fe182..fd6eceb 100755
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -823,6 +823,14 @@
 
         mHasNavigationBar = mContext.getResources().getBoolean(
                 com.android.internal.R.bool.config_showNavigationBar);
+        // Allow a system property to override this. Used by the emulator.
+        // See also hasNavigationBar().
+        String navBarOverride = SystemProperties.get("qemu.hw.mainkeys");
+        if (! "".equals(navBarOverride)) {
+            if      (navBarOverride.equals("1")) mHasNavigationBar = true;
+            else if (navBarOverride.equals("0")) mHasNavigationBar = false;
+        }
+
         mNavigationBarHeight = mHasNavigationBar
                 ? mContext.getResources().getDimensionPixelSize(
                     com.android.internal.R.dimen.navigation_bar_height)
@@ -3725,6 +3733,12 @@
         return diff;
     }
 
+    // Use this instead of checking config_showNavigationBar so that it can be consistently
+    // overridden by qemu.hw.mainkeys in the emulator.
+    public boolean hasNavigationBar() {
+        return mHasNavigationBar;
+    }
+
     public void dump(String prefix, FileDescriptor fd, PrintWriter pw, String[] args) {
         pw.print(prefix); pw.print("mSafeMode="); pw.print(mSafeMode);
                 pw.print(" mSystemReady="); pw.print(mSystemReady);
diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp
index 171710a..bb0e664 100644
--- a/services/camera/libcameraservice/CameraService.cpp
+++ b/services/camera/libcameraservice/CameraService.cpp
@@ -331,14 +331,8 @@
     Mutex::Autolock lock(mSoundLock);
     sp<MediaPlayer> player = mSoundPlayer[kind];
     if (player != 0) {
-        // do not play the sound if stream volume is 0
-        // (typically because ringer mode is silent).
-        int index;
-        AudioSystem::getStreamVolumeIndex(mAudioStreamType, &index);
-        if (index != 0) {
-            player->seekTo(0);
-            player->start();
-        }
+        player->seekTo(0);
+        player->start();
     }
 }
 
diff --git a/services/java/com/android/server/TextServicesManagerService.java b/services/java/com/android/server/TextServicesManagerService.java
index 788ecda..a653322 100644
--- a/services/java/com/android/server/TextServicesManagerService.java
+++ b/services/java/com/android/server/TextServicesManagerService.java
@@ -691,7 +691,7 @@
                 }
                 ISpellCheckerService spellChecker = ISpellCheckerService.Stub.asInterface(service);
                 final SpellCheckerBindGroup group = mSpellCheckerBindGroups.get(mSciId);
-                if (this == group.mInternalConnection) {
+                if (group != null && this == group.mInternalConnection) {
                     group.onServiceConnected(spellChecker);
                 }
             }
diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java
index 68f0e66..3af3e06 100644
--- a/services/java/com/android/server/wm/WindowManagerService.java
+++ b/services/java/com/android/server/wm/WindowManagerService.java
@@ -9263,6 +9263,11 @@
         }
     }
 
+    @Override
+    public boolean hasNavigationBar() {
+        return mPolicy.hasNavigationBar();
+    }
+
     void dumpInput(FileDescriptor fd, PrintWriter pw, boolean dumpAll) {
         pw.println("WINDOW MANAGER INPUT (dumpsys window input)");
         mInputManager.dump(pw);
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowManager.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowManager.java
index 44bdff3..1e66ca2 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowManager.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowManager.java
@@ -467,4 +467,8 @@
 
     public void dismissKeyguard() {
     }
+
+    public boolean hasNavigationBar() {
+        return false; // should this return something else?
+    }
 }
diff --git a/wifi/java/android/net/wifi/WifiWatchdogStateMachine.java b/wifi/java/android/net/wifi/WifiWatchdogStateMachine.java
index 5d5b9ef..b4cbd01 100644
--- a/wifi/java/android/net/wifi/WifiWatchdogStateMachine.java
+++ b/wifi/java/android/net/wifi/WifiWatchdogStateMachine.java
@@ -92,6 +92,14 @@
     private static final String DEFAULT_WALLED_GARDEN_URL =
             "http://clients3.google.com/generate_204";
     private static final int WALLED_GARDEN_SOCKET_TIMEOUT_MS = 10000;
+
+    /* Some carrier apps might have support captive portal handling. Add some delay to allow
+        app authentication to be done before our test.
+       TODO: This should go away once we provide an API to apps to disable walled garden test
+       for certain SSIDs
+     */
+    private static final int WALLED_GARDEN_START_DELAY_MS = 3000;
+
     private static final int DNS_INTRATEST_PING_INTERVAL_MS = 200;
     /* With some router setups, it takes a few hunder milli-seconds before connection is active */
     private static final int DNS_START_DELAY_MS = 1000;
@@ -101,29 +109,30 @@
     /**
      * Indicates the enable setting of WWS may have changed
      */
-    private static final int EVENT_WATCHDOG_TOGGLED = BASE + 1;
+    private static final int EVENT_WATCHDOG_TOGGLED                 = BASE + 1;
 
     /**
      * Indicates the wifi network state has changed. Passed w/ original intent
      * which has a non-null networkInfo object
      */
-    private static final int EVENT_NETWORK_STATE_CHANGE = BASE + 2;
+    private static final int EVENT_NETWORK_STATE_CHANGE             = BASE + 2;
     /**
      * Indicates the signal has changed. Passed with arg1
      * {@link #mNetEventCounter} and arg2 [raw signal strength]
      */
-    private static final int EVENT_RSSI_CHANGE = BASE + 3;
-    private static final int EVENT_SCAN_RESULTS_AVAILABLE = BASE + 4;
-    private static final int EVENT_WIFI_RADIO_STATE_CHANGE = BASE + 5;
-    private static final int EVENT_WATCHDOG_SETTINGS_CHANGE = BASE + 6;
+    private static final int EVENT_RSSI_CHANGE                      = BASE + 3;
+    private static final int EVENT_SCAN_RESULTS_AVAILABLE           = BASE + 4;
+    private static final int EVENT_WIFI_RADIO_STATE_CHANGE          = BASE + 5;
+    private static final int EVENT_WATCHDOG_SETTINGS_CHANGE         = BASE + 6;
 
-    private static final int MESSAGE_HANDLE_WALLED_GARDEN = BASE + 100;
-    private static final int MESSAGE_HANDLE_BAD_AP = BASE + 101;
+    private static final int MESSAGE_HANDLE_WALLED_GARDEN           = BASE + 100;
+    private static final int MESSAGE_HANDLE_BAD_AP                  = BASE + 101;
     /**
      * arg1 == mOnlineWatchState.checkCount
      */
-    private static final int MESSAGE_SINGLE_DNS_CHECK = BASE + 103;
-    private static final int MESSAGE_NETWORK_FOLLOWUP = BASE + 104;
+    private static final int MESSAGE_SINGLE_DNS_CHECK               = BASE + 102;
+    private static final int MESSAGE_NETWORK_FOLLOWUP               = BASE + 103;
+    private static final int MESSAGE_DELAYED_WALLED_GARDEN_CHECK    = BASE + 104;
 
     private Context mContext;
     private ContentResolver mContentResolver;
@@ -140,6 +149,7 @@
     private DnsCheckingState mDnsCheckingState = new DnsCheckingState();
     private OnlineWatchState mOnlineWatchState = new OnlineWatchState();
     private DnsCheckFailureState mDnsCheckFailureState = new DnsCheckFailureState();
+    private DelayWalledGardenState mDelayWalledGardenState = new DelayWalledGardenState();
     private WalledGardenState mWalledGardenState = new WalledGardenState();
     private BlacklistedApState mBlacklistedApState = new BlacklistedApState();
 
@@ -209,6 +219,7 @@
                 addState(mConnectedState, mWatchdogEnabledState);
                     addState(mDnsCheckingState, mConnectedState);
                     addState(mDnsCheckFailureState, mConnectedState);
+                    addState(mDelayWalledGardenState, mConnectedState);
                     addState(mWalledGardenState, mConnectedState);
                     addState(mBlacklistedApState, mConnectedState);
                     addState(mOnlineWatchState, mConnectedState);
@@ -727,14 +738,7 @@
                     return HANDLED;
                 }
 
-                mLastWalledGardenCheckTime = SystemClock.elapsedRealtime();
-                if (isWalledGardenConnection()) {
-                    if (DBG) log("Walled garden test complete - walled garden detected");
-                    transitionTo(mWalledGardenState);
-                } else {
-                    if (DBG) log("Walled garden test complete - online");
-                    transitionTo(mOnlineWatchState);
-                }
+                transitionTo(mDelayWalledGardenState);
                 return HANDLED;
             }
 
@@ -780,6 +784,31 @@
         }
     }
 
+    class DelayWalledGardenState extends State {
+        @Override
+        public void enter() {
+            sendMessageDelayed(MESSAGE_DELAYED_WALLED_GARDEN_CHECK, WALLED_GARDEN_START_DELAY_MS);
+        }
+
+        @Override
+        public boolean processMessage(Message msg) {
+            switch (msg.what) {
+                case MESSAGE_DELAYED_WALLED_GARDEN_CHECK:
+                    mLastWalledGardenCheckTime = SystemClock.elapsedRealtime();
+                    if (isWalledGardenConnection()) {
+                        if (DBG) log("Walled garden test complete - walled garden detected");
+                        transitionTo(mWalledGardenState);
+                    } else {
+                        if (DBG) log("Walled garden test complete - online");
+                        transitionTo(mOnlineWatchState);
+                    }
+                    return HANDLED;
+                default:
+                    return NOT_HANDLED;
+            }
+        }
+    }
+
     class OnlineWatchState extends State {
         /**
          * Signals a short-wait message is enqueued for the current 'guard' counter