Merge "Handle the case of Preference lists that have header views inserted at the top."
diff --git a/core/java/android/text/SpannableStringBuilder.java b/core/java/android/text/SpannableStringBuilder.java
index fdbec20..231f913 100644
--- a/core/java/android/text/SpannableStringBuilder.java
+++ b/core/java/android/text/SpannableStringBuilder.java
@@ -710,18 +710,17 @@
 
         for (int i = 0; i < spanCount; i++) {
             int spanStart = starts[i];
-            int spanEnd = ends[i];
-
             if (spanStart > gapstart) {
                 spanStart -= gaplen;
             }
-            if (spanEnd > gapstart) {
-                spanEnd -= gaplen;
-            }
-
             if (spanStart > queryEnd) {
                 continue;
             }
+
+            int spanEnd = ends[i];
+            if (spanEnd > gapstart) {
+                spanEnd -= gaplen;
+            }
             if (spanEnd < queryStart) {
                 continue;
             }
diff --git a/core/java/android/text/style/SpellCheckSpan.java b/core/java/android/text/style/SpellCheckSpan.java
index caaae99..0d8a103 100644
--- a/core/java/android/text/style/SpellCheckSpan.java
+++ b/core/java/android/text/style/SpellCheckSpan.java
@@ -39,8 +39,8 @@
         mSpellCheckInProgress = (src.readInt() != 0);
     }
 
-    public void setSpellCheckInProgress() {
-        mSpellCheckInProgress = true;
+    public void setSpellCheckInProgress(boolean inProgress) {
+        mSpellCheckInProgress = inProgress;
     }
 
     public boolean isSpellCheckInProgress() {
diff --git a/core/java/android/view/Window.java b/core/java/android/view/Window.java
index 75c7592..d0841dd 100644
--- a/core/java/android/view/Window.java
+++ b/core/java/android/view/Window.java
@@ -26,6 +26,7 @@
 import android.net.Uri;
 import android.os.Bundle;
 import android.os.IBinder;
+import android.os.SystemProperties;
 import android.util.Slog;
 import android.view.accessibility.AccessibilityEvent;
 
@@ -472,11 +473,14 @@
     }
 
     private class LocalWindowManager extends WindowManagerImpl.CompatModeWrapper {
+        private static final String PROPERTY_HARDWARE_UI = "persist.sys.ui.hw";
+
         private final boolean mHardwareAccelerated;
 
         LocalWindowManager(WindowManager wm, boolean hardwareAccelerated) {
             super(wm, getCompatInfo(mContext));
-            mHardwareAccelerated = hardwareAccelerated;
+            mHardwareAccelerated = hardwareAccelerated ||
+                    SystemProperties.getBoolean(PROPERTY_HARDWARE_UI, false);
         }
 
         public boolean isHardwareAccelerated() {
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 530b230..370cce4 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -4308,7 +4308,7 @@
             selectionDone();
         }
         mOrientation = newConfig.orientation;
-        contentInvalidateAll();
+        mWebViewCore.sendMessage(EventHub.CLEAR_CONTENT);
     }
 
     /**
diff --git a/core/java/android/widget/GridLayout.java b/core/java/android/widget/GridLayout.java
index ba69288..fb9047b 100644
--- a/core/java/android/widget/GridLayout.java
+++ b/core/java/android/widget/GridLayout.java
@@ -850,32 +850,65 @@
         return c.getVisibility() == View.GONE;
     }
 
-    private void measureChildWithMargins(View child, int widthMeasureSpec, int heightMeasureSpec) {
-        LayoutParams lp = getLayoutParams(child);
-        int childWidthMeasureSpec = getChildMeasureSpec(widthMeasureSpec,
-                mPaddingLeft + mPaddingRight + getTotalMargin(child, true), lp.width);
-        int childHeightMeasureSpec = getChildMeasureSpec(heightMeasureSpec,
-                mPaddingTop + mPaddingBottom + getTotalMargin(child, false), lp.height);
-        child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
+    private void measureChildWithMargins2(View child, int parentWidthSpec, int parentHeightSpec,
+                                          int childWidth, int childHeight) {
+        int childWidthSpec = getChildMeasureSpec(parentWidthSpec,
+                mPaddingLeft + mPaddingRight + getTotalMargin(child, true), childWidth);
+        int childHeightSpec = getChildMeasureSpec(parentHeightSpec,
+                mPaddingTop + mPaddingBottom + getTotalMargin(child, false), childHeight);
+        child.measure(childWidthSpec, childHeightSpec);
     }
 
-    private void measureChildrenWithMargins(int widthMeasureSpec, int heightMeasureSpec) {
+    private void measureChildrenWithMargins(int widthSpec, int heightSpec, boolean firstPass) {
         for (int i = 0, N = getChildCount(); i < N; i++) {
             View c = getChildAt(i);
             if (isGone(c)) continue;
-            measureChildWithMargins(c, widthMeasureSpec, heightMeasureSpec);
+            LayoutParams lp = getLayoutParams(c);
+            if (firstPass) {
+                measureChildWithMargins2(c, widthSpec, heightSpec, lp.width, lp.height);
+            } else {
+                Spec spec = (orientation == HORIZONTAL) ? lp.columnSpec : lp.rowSpec;
+                if (spec.alignment == FILL) {
+                    Interval span = spec.span;
+                    Axis axis = (orientation == HORIZONTAL) ? horizontalAxis : verticalAxis;
+                    int[] locations = axis.getLocations();
+                    int size = locations[span.max] - locations[span.min];
+                    if (orientation == HORIZONTAL) {
+                        measureChildWithMargins2(c, widthSpec, heightSpec, size, lp.height);
+                    } else {
+                        measureChildWithMargins2(c, widthSpec, heightSpec, lp.width, size);
+                    }
+                }
+            }
         }
     }
 
     @Override
     protected void onMeasure(int widthSpec, int heightSpec) {
-        measureChildrenWithMargins(widthSpec, heightSpec);
+        /** If we have been called by {@link View#measure(int, int)}, one of width or height
+         *  is  likely to have changed. We must invalidate if so. */
+        invalidateValues();
 
-        int width = getPaddingLeft() + horizontalAxis.getMeasure(widthSpec) + getPaddingRight();
-        int height = getPaddingTop() + verticalAxis.getMeasure(heightSpec) + getPaddingBottom();
+        measureChildrenWithMargins(widthSpec, heightSpec, true);
 
-        int measuredWidth = Math.max(width, getSuggestedMinimumWidth());
-        int measuredHeight = Math.max(height, getSuggestedMinimumHeight());
+        int width, height;
+
+        // Use the orientation property to decide which axis should be laid out first.
+        if (orientation == HORIZONTAL) {
+            width = horizontalAxis.getMeasure(widthSpec);
+            measureChildrenWithMargins(widthSpec, heightSpec, false);
+            height = verticalAxis.getMeasure(heightSpec);
+        } else {
+            height = verticalAxis.getMeasure(heightSpec);
+            measureChildrenWithMargins(widthSpec, heightSpec, false);
+            width = horizontalAxis.getMeasure(widthSpec);
+        }
+
+        int hPadding = getPaddingLeft() + getPaddingRight();
+        int vPadding = getPaddingTop() + getPaddingBottom();
+
+        int measuredWidth = Math.max(hPadding + width, getSuggestedMinimumWidth());
+        int measuredHeight = Math.max(vPadding + height, getSuggestedMinimumHeight());
 
         setMeasuredDimension(
                 resolveSizeAndState(measuredWidth, widthSpec, 0),
@@ -1015,8 +1048,6 @@
      for the vertical one.
      */
     final class Axis {
-        private static final int MIN_VALUE = -1000000;
-
         private static final int NEW = 0;
         private static final int PENDING = 1;
         private static final int COMPLETE = 2;
@@ -1024,7 +1055,7 @@
         public final boolean horizontal;
 
         public int definedCount = UNDEFINED;
-        private int inferredCount = UNDEFINED;
+        private int maxIndex = UNDEFINED;
 
         PackedMap<Spec, Bounds> groupBounds;
         public boolean groupBoundsValid = false;
@@ -1056,28 +1087,29 @@
             this.horizontal = horizontal;
         }
 
-        private int maxIndex() {
-            // note the number Integer.MIN_VALUE + 1 comes up in undefined cells
-            int count = -1;
+        private int calculateMaxIndex() {
+            // the number Integer.MIN_VALUE + 1 comes up in undefined cells
+            int result = -1;
             for (int i = 0, N = getChildCount(); i < N; i++) {
                 View c = getChildAt(i);
                 LayoutParams params = getLayoutParams(c);
                 Spec spec = horizontal ? params.columnSpec : params.rowSpec;
-                count = max(count, spec.span.min);
-                count = max(count, spec.span.max);
+                Interval span = spec.span;
+                result = max(result, span.min);
+                result = max(result, span.max);
             }
-            return count == -1 ? UNDEFINED : count;
+            return result == -1 ? UNDEFINED : result;
         }
 
-        private int getInferredCount() {
-            if (inferredCount == UNDEFINED) {
-                inferredCount = max(0, maxIndex()); // if there are no cells, actual count is zero
+        private int getMaxIndex() {
+            if (maxIndex == UNDEFINED) {
+                maxIndex = max(0, calculateMaxIndex()); // use zero when there are no children
             }
-            return inferredCount;
+            return maxIndex;
         }
 
         public int getCount() {
-            return max(definedCount, getInferredCount());
+            return max(definedCount, getMaxIndex());
         }
 
         public void setCount(int count) {
@@ -1179,7 +1211,7 @@
         }
 
         private void include(List<Arc> arcs, Interval key, MutableInt size,
-                boolean ignoreIfAlreadyPresent) {
+                             boolean ignoreIfAlreadyPresent) {
             /*
             Remove self referential links.
             These appear:
@@ -1341,19 +1373,18 @@
         }
 
         private void init(int[] locations) {
-            Arrays.fill(locations, MIN_VALUE);
-            locations[0] = 0;
+            Arrays.fill(locations, 0);
         }
 
         private String arcsToString(List<Arc> arcs) {
-            String var = horizontal ? "c" : "r";
+            String var = horizontal ? "x" : "y";
             StringBuilder result = new StringBuilder();
-            boolean first = false;
-            for(Arc arc : arcs) {
-                if (!first) {
-                    first = true;
+            boolean first = true;
+            for (Arc arc : arcs) {
+                if (first) {
+                    first = false;
                 } else {
-                    result =result.append(", ");
+                    result = result.append(", ");
                 }
                 int src = arc.span.min;
                 int dst = arc.span.max;
@@ -1434,10 +1465,6 @@
                         if (originalCulprits != null) {
                             logError(axisName, arcs, originalCulprits);
                         }
-                        if (DEBUG) {
-                            Log.v(TAG, axisName + " iteration completed in " +
-                                    (1 + i) + " steps of " + N);
-                        }
                         return;
                     }
                 }
@@ -1506,6 +1533,18 @@
 
         private void computeLocations(int[] a) {
             solve(getArcs(), a);
+            if (!orderPreserved) {
+                // Solve returns the smallest solution to the constraint system for which all
+                // values are positive. One value is therefore zero - though if the row/col
+                // order is not preserved this may not be the first vertex. For consistency,
+                // translate all the values so that they measure the distance from a[0]; the
+                // leading edge of the parent. After this transformation some values may be
+                // negative.
+                int a0 = a[0];
+                for (int i = 0, N = a.length; i < N; i++) {
+                    a[i] = a[i] - a0;
+                }
+            }
         }
 
         public int[] getLocations() {
@@ -1521,7 +1560,10 @@
         }
 
         private int size(int[] locations) {
-            return max2(locations, 0) - locations[0];
+            // The parental edges are attached to vertices 0 and N - even when order is not
+            // being preserved and other vertices fall outside this range. Measure the distance
+            // between vertices 0 and N, assuming that locations[0] = 0.
+            return locations[getCount()];
         }
 
         private void setParentConstraints(int min, int max) {
@@ -1561,7 +1603,7 @@
         }
 
         public void invalidateStructure() {
-            inferredCount = UNDEFINED;
+            maxIndex = UNDEFINED;
 
             groupBounds = null;
             forwardLinks = null;
@@ -2139,8 +2181,8 @@
 
     /**
      * A Spec defines the horizontal or vertical characteristics of a group of
-     * cells. Each spec. defines the <em>grid indices</em>, <em>alignment</em> and
-     * <em>flexibility</em> along the appropriate axis.
+     * cells. Each spec. defines the <em>grid indices</em> and <em>alignment</em>
+     * along the appropriate axis.
      * <p>
      * The <em>grid indices</em> are the leading and trailing edges of this cell group.
      * See {@link GridLayout} for a description of the conventions used by GridLayout
@@ -2149,6 +2191,15 @@
      * The <em>alignment</em> property specifies how cells should be aligned in this group.
      * For row groups, this specifies the vertical alignment.
      * For column groups, this specifies the horizontal alignment.
+     * <p>
+     * Use the following static methods to create specs:
+     * <ul>
+     *   <li>{@link #spec(int)}</li>
+     *   <li>{@link #spec(int, int)}</li>
+     *   <li>{@link #spec(int, Alignment)}</li>
+     *   <li>{@link #spec(int, int, Alignment)}</li>
+     * </ul>
+     *
      */
     public static class Spec {
         static final Spec UNDEFINED = spec(GridLayout.UNDEFINED);
diff --git a/core/java/android/widget/Space.java b/core/java/android/widget/Space.java
index d7b2ec2..bb53a77 100644
--- a/core/java/android/widget/Space.java
+++ b/core/java/android/widget/Space.java
@@ -32,20 +32,24 @@
      */
     public Space(Context context, AttributeSet attrs, int defStyle) {
         super(context, attrs, defStyle);
+        if (getVisibility() == VISIBLE) {
+            setVisibility(INVISIBLE);
+        }
     }
 
     /**
      * {@inheritDoc}
      */
     public Space(Context context, AttributeSet attrs) {
-        super(context, attrs);
+        this(context, attrs, 0);
     }
 
     /**
      * {@inheritDoc}
      */
     public Space(Context context) {
-        super(context);
+        //noinspection NullableProblems
+        this(context, null);
     }
 
     /**
@@ -58,22 +62,6 @@
     }
 
     /**
-     * {@inheritDoc}
-     */
-    @Override
-    public ViewGroup.LayoutParams getLayoutParams() {
-        return super.getLayoutParams();
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public void setLayoutParams(ViewGroup.LayoutParams params) {
-        super.setLayoutParams(params);
-    }
-
-    /**
      * Compare to: {@link View#getDefaultSize(int, int)}
      * If mode is AT_MOST, return the child size instead of the parent size
      * (unless it is too big).
diff --git a/core/java/android/widget/SpellChecker.java b/core/java/android/widget/SpellChecker.java
index 6b2f3e4..5d8db2f 100644
--- a/core/java/android/widget/SpellChecker.java
+++ b/core/java/android/widget/SpellChecker.java
@@ -22,7 +22,6 @@
 import android.text.Spanned;
 import android.text.style.SpellCheckSpan;
 import android.text.style.SuggestionSpan;
-import android.util.Log;
 import android.view.textservice.SpellCheckerSession;
 import android.view.textservice.SpellCheckerSession.SpellCheckerSessionListener;
 import android.view.textservice.SuggestionsInfo;
@@ -40,23 +39,21 @@
  * @hide
  */
 public class SpellChecker implements SpellCheckerSessionListener {
-    private static final String LOG_TAG = "SpellChecker";
-    private static final boolean DEBUG_SPELL_CHECK = false;
-    private static final int DELAY_BEFORE_SPELL_CHECK = 400; // milliseconds
 
     private final TextView mTextView;
 
     final SpellCheckerSession mSpellCheckerSession;
     final int mCookie;
 
-    // Paired arrays for the (id, spellCheckSpan) pair. mIndex is the next available position
+    // Paired arrays for the (id, spellCheckSpan) pair. A negative id means the associated
+    // SpellCheckSpan has been recycled and can be-reused.
+    // May contain null SpellCheckSpans after a given index.
     private int[] mIds;
     private SpellCheckSpan[] mSpellCheckSpans;
-    // The actual current number of used slots in the above arrays
+    // The mLength first elements of the above arrays have been initialized
     private int mLength;
 
     private int mSpanSequenceCounter = 0;
-    private Runnable mChecker;
 
     public SpellChecker(TextView textView) {
         mTextView = textView;
@@ -69,7 +66,7 @@
         mCookie = hashCode();
 
         // Arbitrary: 4 simultaneous spell check spans. Will automatically double size on demand
-        final int size = ArrayUtils.idealObjectArraySize(4);
+        final int size = ArrayUtils.idealObjectArraySize(1);
         mIds = new int[size];
         mSpellCheckSpans = new SpellCheckSpan[size];
         mLength = 0;
@@ -89,73 +86,50 @@
         }
     }
 
-    public void addSpellCheckSpan(SpellCheckSpan spellCheckSpan) {
-        int length = mIds.length;
-        if (mLength >= length) {
-            final int newSize = length * 2;
+    private int nextSpellCheckSpanIndex() {
+        for (int i = 0; i < mLength; i++) {
+            if (mIds[i] < 0) return i;
+        }
+
+        if (mLength == mSpellCheckSpans.length) {
+            final int newSize = mLength * 2;
             int[] newIds = new int[newSize];
             SpellCheckSpan[] newSpellCheckSpans = new SpellCheckSpan[newSize];
-            System.arraycopy(mIds, 0, newIds, 0, length);
-            System.arraycopy(mSpellCheckSpans, 0, newSpellCheckSpans, 0, length);
+            System.arraycopy(mIds, 0, newIds, 0, mLength);
+            System.arraycopy(mSpellCheckSpans, 0, newSpellCheckSpans, 0, mLength);
             mIds = newIds;
             mSpellCheckSpans = newSpellCheckSpans;
         }
 
-        mIds[mLength] = mSpanSequenceCounter++;
-        mSpellCheckSpans[mLength] = spellCheckSpan;
+        mSpellCheckSpans[mLength] = new SpellCheckSpan();
         mLength++;
+        return mLength - 1;
+    }
 
-        if (DEBUG_SPELL_CHECK) {
-            final Editable mText = (Editable) mTextView.getText();
-            int start = mText.getSpanStart(spellCheckSpan);
-            int end = mText.getSpanEnd(spellCheckSpan);
-            if (start >= 0 && end >= 0) {
-                Log.d(LOG_TAG, "Schedule check " + mText.subSequence(start, end));
-            } else {
-                Log.d(LOG_TAG, "Schedule check   EMPTY!");
-            }
-        }
-
-        scheduleSpellCheck();
+    public void addSpellCheckSpan(int wordStart, int wordEnd) {
+        final int index = nextSpellCheckSpanIndex();
+        ((Editable) mTextView.getText()).setSpan(mSpellCheckSpans[index], wordStart, wordEnd,
+                Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
+        mIds[index] = mSpanSequenceCounter++;
     }
 
     public void removeSpellCheckSpan(SpellCheckSpan spellCheckSpan) {
         for (int i = 0; i < mLength; i++) {
             if (mSpellCheckSpans[i] == spellCheckSpan) {
-                removeAtIndex(i);
+                mSpellCheckSpans[i].setSpellCheckInProgress(false);
+                mIds[i] = -1;
                 return;
             }
         }
     }
 
-    private void removeAtIndex(int i) {
-        System.arraycopy(mIds, i + 1, mIds, i, mLength - i - 1);
-        System.arraycopy(mSpellCheckSpans, i + 1, mSpellCheckSpans, i, mLength - i - 1);
-        mLength--;
-    }
-
     public void onSelectionChanged() {
-        scheduleSpellCheck();
+        spellCheck();
     }
 
-    private void scheduleSpellCheck() {
-        if (mLength == 0) return;
+    public void spellCheck() {
         if (mSpellCheckerSession == null) return;
 
-        if (mChecker != null) {
-            mTextView.removeCallbacks(mChecker);
-        }
-        if (mChecker == null) {
-            mChecker = new Runnable() {
-                public void run() {
-                  spellCheck();
-                }
-            };
-        }
-        mTextView.postDelayed(mChecker, DELAY_BEFORE_SPELL_CHECK);
-    }
-
-    private void spellCheck() {
         final Editable editable = (Editable) mTextView.getText();
         final int selectionStart = Selection.getSelectionStart(editable);
         final int selectionEnd = Selection.getSelectionEnd(editable);
@@ -164,8 +138,7 @@
         int textInfosCount = 0;
 
         for (int i = 0; i < mLength; i++) {
-            SpellCheckSpan spellCheckSpan = mSpellCheckSpans[i];
-
+            final SpellCheckSpan spellCheckSpan = mSpellCheckSpans[i];
             if (spellCheckSpan.isSpellCheckInProgress()) continue;
 
             final int start = editable.getSpanStart(spellCheckSpan);
@@ -174,7 +147,7 @@
             // Do not check this word if the user is currently editing it
             if (start >= 0 && end > start && (selectionEnd < start || selectionStart > end)) {
                 final String word = editable.subSequence(start, end).toString();
-                spellCheckSpan.setSpellCheckInProgress();
+                spellCheckSpan.setSpellCheckInProgress(true);
                 textInfos[textInfosCount++] = new TextInfo(word, mCookie, mIds[i]);
             }
         }
@@ -196,27 +169,18 @@
         for (int i = 0; i < results.length; i++) {
             SuggestionsInfo suggestionsInfo = results[i];
             if (suggestionsInfo.getCookie() != mCookie) continue;
-
             final int sequenceNumber = suggestionsInfo.getSequence();
-            // Starting from the end, to limit the number of array copy while removing
-            for (int j = mLength - 1; j >= 0; j--) {
+
+            for (int j = 0; j < mLength; j++) {
+                final SpellCheckSpan spellCheckSpan = mSpellCheckSpans[j];
+
                 if (sequenceNumber == mIds[j]) {
-                    SpellCheckSpan spellCheckSpan = mSpellCheckSpans[j];
                     final int attributes = suggestionsInfo.getSuggestionsAttributes();
                     boolean isInDictionary =
                             ((attributes & SuggestionsInfo.RESULT_ATTR_IN_THE_DICTIONARY) > 0);
                     boolean looksLikeTypo =
                             ((attributes & SuggestionsInfo.RESULT_ATTR_LOOKS_LIKE_TYPO) > 0);
 
-                    if (DEBUG_SPELL_CHECK) {
-                        final int start = editable.getSpanStart(spellCheckSpan);
-                        final int end = editable.getSpanEnd(spellCheckSpan);
-                        Log.d(LOG_TAG, "Result sequence=" + suggestionsInfo.getSequence() + " " +
-                                editable.subSequence(start, end) +
-                                "\t" + (isInDictionary?"IN_DICT" : "NOT_DICT") +
-                                "\t" + (looksLikeTypo?"TYPO" : "NOT_TYPO"));
-                    }
-
                     if (!isInDictionary && looksLikeTypo) {
                         String[] suggestions = getSuggestions(suggestionsInfo);
                         if (suggestions.length > 0) {
@@ -230,13 +194,6 @@
                                     Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
                             // TODO limit to the word rectangle region
                             mTextView.invalidate();
-
-                            if (DEBUG_SPELL_CHECK) {
-                                String suggestionsString = "";
-                                for (String s : suggestions) { suggestionsString += s + "|"; }
-                                Log.d(LOG_TAG, "  Suggestions for " + sequenceNumber + " " +
-                                    editable.subSequence(start, end)+ "  " + suggestionsString);
-                            }
                         }
                     }
                     editable.removeSpan(spellCheckSpan);
@@ -246,9 +203,10 @@
     }
 
     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) {
+        for (int j = 0; j < len; j++) {
             suggestions[j] = suggestionsInfo.getSuggestionAt(j);
         }
         return suggestions;
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index bffdadc..cde36c8 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -5537,7 +5537,7 @@
     @Override public boolean onCheckIsTextEditor() {
         return mInputType != EditorInfo.TYPE_NULL;
     }
-    
+
     @Override public InputConnection onCreateInputConnection(EditorInfo outAttrs) {
         if (onCheckIsTextEditor() && isEnabled()) {
             if (mInputMethodState == null) {
@@ -7492,9 +7492,6 @@
      */
     protected void onSelectionChanged(int selStart, int selEnd) {
         sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_TEXT_SELECTION_CHANGED);
-        if (mSpellChecker != null) {
-            mSpellChecker.onSelectionChanged();
-        }
     }
 
     /**
@@ -7553,6 +7550,8 @@
         for (int i = 0; i < length; i++) {
             final int s = text.getSpanStart(spans[i]);
             final int e = text.getSpanEnd(spans[i]);
+            // Spans that are adjacent to the edited region will be handled in
+            // updateSpellCheckSpans. Result depends on what will be added (space or text)
             if (e == start || s == end) break;
             text.removeSpan(spans[i]);
         }
@@ -7735,12 +7734,8 @@
             }
         }
 
-        if (what instanceof SpellCheckSpan) {
-            if (newStart < 0) {
-                getSpellChecker().removeSpellCheckSpan((SpellCheckSpan) what);
-            } else if (oldStart < 0) {
-                getSpellChecker().addSpellCheckSpan((SpellCheckSpan) what);
-            }
+        if (newStart < 0 && what instanceof SpellCheckSpan) {
+            getSpellChecker().removeSpellCheckSpan((SpellCheckSpan) what);
         }
     }
 
@@ -7750,8 +7745,8 @@
     private void updateSpellCheckSpans(int start, int end) {
         if (!isTextEditable() || !isSuggestionsEnabled() || !getSpellChecker().isSessionActive())
             return;
-        Editable text = (Editable) mText;
 
+        Editable text = (Editable) mText;
         WordIterator wordIterator = getWordIterator();
         wordIterator.setCharSequence(text);
 
@@ -7770,57 +7765,75 @@
             return;
         }
 
+        // We need to expand by one character because we want to include the spans that end/start
+        // at position start/end respectively.
+        SpellCheckSpan[] spellCheckSpans = text.getSpans(start - 1, end + 1, SpellCheckSpan.class);
+        SuggestionSpan[] suggestionSpans = text.getSpans(start - 1, end + 1, SuggestionSpan.class);
+        final int numberOfSpellCheckSpans = spellCheckSpans.length;
+
         // Iterate over the newly added text and schedule new SpellCheckSpans
         while (wordStart <= end) {
             if (wordEnd >= start) {
-                // A word across the interval boundaries must remove boundary edition spans
+                // A new word has been created across the interval boundaries. Remove previous spans
                 if (wordStart < start && wordEnd > start) {
-                    removeEditionSpansAt(start, text);
+                    removeSpansAt(start, spellCheckSpans, text);
+                    removeSpansAt(start, suggestionSpans, text);
                 }
 
                 if (wordStart < end && wordEnd > end) {
-                    removeEditionSpansAt(end, text);
+                    removeSpansAt(end, spellCheckSpans, text);
+                    removeSpansAt(end, suggestionSpans, text);
                 }
 
                 // Do not create new boundary spans if they already exist
                 boolean createSpellCheckSpan = true;
                 if (wordEnd == start) {
-                    SpellCheckSpan[] spellCheckSpans = text.getSpans(start, start,
-                            SpellCheckSpan.class);
-                    if (spellCheckSpans.length > 0) createSpellCheckSpan = false;
+                    for (int i = 0; i < numberOfSpellCheckSpans; i++) {
+                        final int spanEnd = text.getSpanEnd(spellCheckSpans[i]);
+                        if (spanEnd == start) {
+                            createSpellCheckSpan = false;
+                            break;
+                        }
+                    }
                 }
 
                 if (wordStart == end) {
-                    SpellCheckSpan[] spellCheckSpans = text.getSpans(end, end,
-                            SpellCheckSpan.class);
-                    if (spellCheckSpans.length > 0) createSpellCheckSpan = false;
+                    for (int i = 0; i < numberOfSpellCheckSpans; i++) {
+                        final int spanStart = text.getSpanEnd(spellCheckSpans[i]);
+                        if (spanStart == end) {
+                            createSpellCheckSpan = false;
+                            break;
+                        }
+                    }
                 }
 
                 if (createSpellCheckSpan) {
-                    text.setSpan(new SpellCheckSpan(), wordStart, wordEnd,
-                            Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
+                    mSpellChecker.addSpellCheckSpan(wordStart, wordEnd);
                 }
             }
 
             // iterate word by word
             wordEnd = wordIterator.following(wordEnd);
-            if (wordEnd == BreakIterator.DONE) return;
+            if (wordEnd == BreakIterator.DONE) break;
             wordStart = wordIterator.getBeginning(wordEnd);
             if (wordStart == BreakIterator.DONE) {
                 Log.e(LOG_TAG, "Unable to find word beginning from " + wordEnd + "in " + mText);
-                return;
+                break;
             }
         }
+
+        mSpellChecker.spellCheck();
     }
 
-    private static void removeEditionSpansAt(int offset, Editable text) {
-        SuggestionSpan[] suggestionSpans = text.getSpans(offset, offset, SuggestionSpan.class);
-        for (int i = 0; i < suggestionSpans.length; i++) {
-            text.removeSpan(suggestionSpans[i]);
-        }
-        SpellCheckSpan[] spellCheckSpans = text.getSpans(offset, offset, SpellCheckSpan.class);
-        for (int i = 0; i < spellCheckSpans.length; i++) {
-            text.removeSpan(spellCheckSpans[i]);
+    private static <T> void removeSpansAt(int offset, T[] spans, Editable text) {
+        final int length = spans.length;
+        for (int i = 0; i < length; i++) {
+            final T span = spans[i];
+            final int start = text.getSpanStart(span);
+            if (start > offset) continue;
+            final int end = text.getSpanEnd(span);
+            if (end < offset) continue;
+            text.removeSpan(span);
         }
     }
 
@@ -8381,6 +8394,10 @@
                 boolean selectAllGotFocus = mSelectAllOnFocus && didTouchFocusSelect();
                 hideControllers();
                 if (!selectAllGotFocus && mText.length() > 0) {
+                    if (mSpellChecker != null) {
+                        // When the cursor moves, the word that was typed may need spell check
+                        mSpellChecker.onSelectionChanged();
+                    }
                     if (isCursorInsideEasyCorrectionSpan()) {
                         showSuggestions();
                     } else if (hasInsertionController()) {
@@ -9596,6 +9613,8 @@
 
     private class SuggestionsPopupWindow extends PinnedPopupWindow implements OnItemClickListener {
         private static final int MAX_NUMBER_SUGGESTIONS = SuggestionSpan.SUGGESTIONS_MAX_SIZE;
+        private static final int ADD_TO_DICTIONARY = -1;
+        private static final int DELETE_TEXT = -2;
         private SuggestionInfo[] mSuggestionInfos;
         private int mNumberOfSuggestions;
         private boolean mCursorWasVisibleBeforeSuggestions;
@@ -9647,9 +9666,9 @@
             listView.setOnItemClickListener(this);
             mContentView = listView;
 
-            // Inflate the suggestion items once and for all. +1 for add to dictionary
-            mSuggestionInfos = new SuggestionInfo[MAX_NUMBER_SUGGESTIONS + 1];
-            for (int i = 0; i < MAX_NUMBER_SUGGESTIONS + 1; i++) {
+            // Inflate the suggestion items once and for all. + 2 for add to dictionary and delete
+            mSuggestionInfos = new SuggestionInfo[MAX_NUMBER_SUGGESTIONS + 2];
+            for (int i = 0; i < mSuggestionInfos.length; i++) {
                 mSuggestionInfos[i] = new SuggestionInfo();
             }
         }
@@ -9700,7 +9719,19 @@
                             false);
                 }
 
-                textView.setText(mSuggestionInfos[position].text);
+                final SuggestionInfo suggestionInfo = mSuggestionInfos[position];
+                textView.setText(suggestionInfo.text);
+
+                if (suggestionInfo.suggestionIndex == ADD_TO_DICTIONARY) {
+                    textView.setCompoundDrawablesWithIntrinsicBounds(
+                            com.android.internal.R.drawable.ic_suggestions_add, 0, 0, 0);
+                } else if (suggestionInfo.suggestionIndex == DELETE_TEXT) {
+                    textView.setCompoundDrawablesWithIntrinsicBounds(
+                            com.android.internal.R.drawable.ic_suggestions_delete, 0, 0, 0);
+                } else {
+                    textView.setCompoundDrawables(null, null, null, null);
+                }
+
                 return textView;
             }
         }
@@ -9751,11 +9782,10 @@
         public void show() {
             if (!(mText instanceof Editable)) return;
 
-            if (updateSuggestions()) {
-                mCursorWasVisibleBeforeSuggestions = mCursorVisible;
-                setCursorVisible(false);
-                super.show();
-            }
+            updateSuggestions();
+            mCursorWasVisibleBeforeSuggestions = mCursorVisible;
+            setCursorVisible(false);
+            super.show();
         }
 
         @Override
@@ -9811,7 +9841,7 @@
             super.hide();
         }
 
-        private boolean updateSuggestions() {
+        private void updateSuggestions() {
             Spannable spannable = (Spannable) TextView.this.mText;
             SuggestionSpan[] suggestionSpans = getSuggestionSpans();
 
@@ -9860,13 +9890,14 @@
                 highlightTextDifferences(mSuggestionInfos[i], spanUnionStart, spanUnionEnd);
             }
 
+            // Add to dictionary item is there a span with the misspelled flag
             if (misspelledSpan != null) {
                 final int misspelledStart = spannable.getSpanStart(misspelledSpan);
                 final int misspelledEnd = spannable.getSpanEnd(misspelledSpan);
                 if (misspelledStart >= 0 && misspelledEnd > misspelledStart) {
                     SuggestionInfo suggestionInfo = mSuggestionInfos[mNumberOfSuggestions];
                     suggestionInfo.suggestionSpan = misspelledSpan;
-                    suggestionInfo.suggestionIndex = -1;
+                    suggestionInfo.suggestionIndex = ADD_TO_DICTIONARY;
                     suggestionInfo.text.replace(0, suggestionInfo.text.length(),
                             getContext().getString(com.android.internal.R.string.addToDictionary));
 
@@ -9874,7 +9905,13 @@
                 }
             }
 
-            if (mNumberOfSuggestions == 0) return false;
+            // Delete item
+            SuggestionInfo suggestionInfo = mSuggestionInfos[mNumberOfSuggestions];
+            suggestionInfo.suggestionSpan = null;
+            suggestionInfo.suggestionIndex = DELETE_TEXT;
+            suggestionInfo.text.replace(0, suggestionInfo.text.length(),
+                    getContext().getString(com.android.internal.R.string.deleteText));
+            mNumberOfSuggestions++;
 
             if (mSuggestionRangeSpan == null) mSuggestionRangeSpan = new SuggestionRangeSpan();
             if (underlineColor == 0) {
@@ -9890,8 +9927,6 @@
                     Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
 
             mSuggestionsAdapter.notifyDataSetChanged();
-
-            return true;
         }
 
         private void highlightTextDifferences(SuggestionInfo suggestionInfo, int unionStart,
@@ -9916,77 +9951,94 @@
 
         @Override
         public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
-            hide();
+            TextView textView = (TextView) view;
+            Editable editable = (Editable) mText;
 
-            if (view instanceof TextView) {
-                TextView textView = (TextView) view;
-                Editable editable = (Editable) mText;
+            SuggestionInfo suggestionInfo = mSuggestionInfos[position];
 
-                SuggestionInfo suggestionInfo = mSuggestionInfos[position];
-                final int spanStart = editable.getSpanStart(suggestionInfo.suggestionSpan);
-                final int spanEnd = editable.getSpanEnd(suggestionInfo.suggestionSpan);
-                if (spanStart < 0 || spanEnd < 0) return; // Span has been removed
-                final String originalText = mText.subSequence(spanStart, spanEnd).toString();
-
-                if (suggestionInfo.suggestionIndex < 0) {
-                    Intent intent = new Intent(Settings.ACTION_USER_DICTIONARY_INSERT);
-                    intent.putExtra("word", originalText);
-                    intent.setFlags(intent.getFlags() | Intent.FLAG_ACTIVITY_NEW_TASK);
-                    getContext().startActivity(intent);
-                    suggestionInfo.removeMisspelledFlag();
-                } else {
-                    // SuggestionSpans are removed by replace: save them before
-                    SuggestionSpan[] suggestionSpans = editable.getSpans(spanStart, spanEnd,
-                            SuggestionSpan.class);
-                    final int length = suggestionSpans.length;
-                    int[] suggestionSpansStarts = new int[length];
-                    int[] suggestionSpansEnds = new int[length];
-                    int[] suggestionSpansFlags = new int[length];
-                    for (int i = 0; i < length; i++) {
-                        final SuggestionSpan suggestionSpan = suggestionSpans[i];
-                        suggestionSpansStarts[i] = editable.getSpanStart(suggestionSpan);
-                        suggestionSpansEnds[i] = editable.getSpanEnd(suggestionSpan);
-                        suggestionSpansFlags[i] = editable.getSpanFlags(suggestionSpan);
-                    }
-
-                    final int suggestionStart = suggestionInfo.suggestionStart;
-                    final int suggestionEnd = suggestionInfo.suggestionEnd;
-                    final String suggestion = textView.getText().subSequence(
-                            suggestionStart, suggestionEnd).toString();
-                    editable.replace(spanStart, spanEnd, suggestion);
-
-                    suggestionInfo.removeMisspelledFlag();
-
-                    // Notify source IME of the suggestion pick. Do this before swaping texts.
-                    if (!TextUtils.isEmpty(
-                            suggestionInfo.suggestionSpan.getNotificationTargetClassName())) {
-                        InputMethodManager imm = InputMethodManager.peekInstance();
-                        imm.notifySuggestionPicked(suggestionInfo.suggestionSpan, originalText,
-                                suggestionInfo.suggestionIndex);
-                    }
-
-                    // Swap text content between actual text and Suggestion span
-                    String[] suggestions = suggestionInfo.suggestionSpan.getSuggestions();
-                    suggestions[suggestionInfo.suggestionIndex] = originalText;
-
-                    // Restore previous SuggestionSpans
-                    final int lengthDifference = suggestion.length() - (spanEnd - spanStart);
-                    for (int i = 0; i < length; i++) {
-                        // Only spans that include the modified region make sense after replacement
-                        // Spans partially included in the replaced region are removed, there is no
-                        // way to assign them a valid range after replacement
-                        if (suggestionSpansStarts[i] <= spanStart &&
-                                suggestionSpansEnds[i] >= spanEnd) {
-                            editable.setSpan(suggestionSpans[i], suggestionSpansStarts[i],
-                                    suggestionSpansEnds[i] + lengthDifference,
-                                    suggestionSpansFlags[i]);
-                        }
-                    }
-                    
-                    // Move cursor at the end of the replacement word
-                    Selection.setSelection(editable, spanEnd + lengthDifference);
+            if (suggestionInfo.suggestionIndex == DELETE_TEXT) {
+                final int spanUnionStart = editable.getSpanStart(mSuggestionRangeSpan);
+                int spanUnionEnd = editable.getSpanEnd(mSuggestionRangeSpan);
+                // Do not leave two adjacent spaces after deletion, or one at beginning of text
+                if (spanUnionEnd < editable.length() &&
+                        Character.isSpaceChar(editable.charAt(spanUnionEnd)) &&
+                        (spanUnionStart == 0 ||
+                        Character.isSpaceChar(editable.charAt(spanUnionStart - 1)))) {
+                        spanUnionEnd = spanUnionEnd + 1;
                 }
+                editable.replace(spanUnionStart, spanUnionEnd, "");
+                hide();
+                return;
             }
+
+            final int spanStart = editable.getSpanStart(suggestionInfo.suggestionSpan);
+            final int spanEnd = editable.getSpanEnd(suggestionInfo.suggestionSpan);
+            if (spanStart < 0 || spanEnd < 0) {
+                // Span has been removed
+                hide();
+                return;
+            }
+            final String originalText = mText.subSequence(spanStart, spanEnd).toString();
+
+            if (suggestionInfo.suggestionIndex == ADD_TO_DICTIONARY) {
+                Intent intent = new Intent(Settings.ACTION_USER_DICTIONARY_INSERT);
+                intent.putExtra("word", originalText);
+                intent.setFlags(intent.getFlags() | Intent.FLAG_ACTIVITY_NEW_TASK);
+                getContext().startActivity(intent);
+                suggestionInfo.removeMisspelledFlag();
+            } else {
+                // SuggestionSpans are removed by replace: save them before
+                SuggestionSpan[] suggestionSpans = editable.getSpans(spanStart, spanEnd,
+                        SuggestionSpan.class);
+                final int length = suggestionSpans.length;
+                int[] suggestionSpansStarts = new int[length];
+                int[] suggestionSpansEnds = new int[length];
+                int[] suggestionSpansFlags = new int[length];
+                for (int i = 0; i < length; i++) {
+                    final SuggestionSpan suggestionSpan = suggestionSpans[i];
+                    suggestionSpansStarts[i] = editable.getSpanStart(suggestionSpan);
+                    suggestionSpansEnds[i] = editable.getSpanEnd(suggestionSpan);
+                    suggestionSpansFlags[i] = editable.getSpanFlags(suggestionSpan);
+                }
+
+                final int suggestionStart = suggestionInfo.suggestionStart;
+                final int suggestionEnd = suggestionInfo.suggestionEnd;
+                final String suggestion = textView.getText().subSequence(
+                        suggestionStart, suggestionEnd).toString();
+                editable.replace(spanStart, spanEnd, suggestion);
+
+                suggestionInfo.removeMisspelledFlag();
+
+                // Notify source IME of the suggestion pick. Do this before swaping texts.
+                if (!TextUtils.isEmpty(
+                        suggestionInfo.suggestionSpan.getNotificationTargetClassName())) {
+                    InputMethodManager imm = InputMethodManager.peekInstance();
+                    imm.notifySuggestionPicked(suggestionInfo.suggestionSpan, originalText,
+                            suggestionInfo.suggestionIndex);
+                }
+
+                // Swap text content between actual text and Suggestion span
+                String[] suggestions = suggestionInfo.suggestionSpan.getSuggestions();
+                suggestions[suggestionInfo.suggestionIndex] = originalText;
+
+                // Restore previous SuggestionSpans
+                final int lengthDifference = suggestion.length() - (spanEnd - spanStart);
+                for (int i = 0; i < length; i++) {
+                    // Only spans that include the modified region make sense after replacement
+                    // Spans partially included in the replaced region are removed, there is no
+                    // way to assign them a valid range after replacement
+                    if (suggestionSpansStarts[i] <= spanStart &&
+                            suggestionSpansEnds[i] >= spanEnd) {
+                        editable.setSpan(suggestionSpans[i], suggestionSpansStarts[i],
+                                suggestionSpansEnds[i] + lengthDifference, suggestionSpansFlags[i]);
+                    }
+                }
+
+                // Move cursor at the end of the replacement word
+                Selection.setSelection(editable, spanEnd + lengthDifference);
+            }
+
+            hide();
         }
     }
 
diff --git a/core/res/res/drawable-hdpi/ic_suggestions_add.png b/core/res/res/drawable-hdpi/ic_suggestions_add.png
new file mode 100644
index 0000000..79c017a
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_suggestions_add.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_suggestions_delete.png b/core/res/res/drawable-hdpi/ic_suggestions_delete.png
new file mode 100644
index 0000000..1ae6b96
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_suggestions_delete.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_suggestions_add.png b/core/res/res/drawable-mdpi/ic_suggestions_add.png
new file mode 100644
index 0000000..f91951b
--- /dev/null
+++ b/core/res/res/drawable-mdpi/ic_suggestions_add.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_suggestions_delete.png b/core/res/res/drawable-mdpi/ic_suggestions_delete.png
new file mode 100644
index 0000000..98eb565
--- /dev/null
+++ b/core/res/res/drawable-mdpi/ic_suggestions_delete.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_suggestions_add.png b/core/res/res/drawable-xhdpi/ic_suggestions_add.png
new file mode 100644
index 0000000..aac038c
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/ic_suggestions_add.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_suggestions_delete.png b/core/res/res/drawable-xhdpi/ic_suggestions_delete.png
new file mode 100644
index 0000000..077e9fc
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/ic_suggestions_delete.png
Binary files differ
diff --git a/core/res/res/layout/status_bar_latest_event_content_large_icon.xml b/core/res/res/layout/status_bar_latest_event_content_large_icon.xml
index ac4d1e4..f3f1957 100644
--- a/core/res/res/layout/status_bar_latest_event_content_large_icon.xml
+++ b/core/res/res/layout/status_bar_latest_event_content_large_icon.xml
@@ -4,8 +4,8 @@
     android:layout_height="wrap_content"
     android:layout_gravity="center"
     android:orientation="vertical"
-    android:paddingLeft="8dp"
-    android:paddingRight="8dp"
+    android:paddingLeft="12dp"
+    android:paddingRight="12dp"
     >
     <TextView android:id="@+id/title"
         android:textAppearance="@style/TextAppearance.StatusBar.EventContent.Title"
diff --git a/core/res/res/layout/text_edit_suggestion_item.xml b/core/res/res/layout/text_edit_suggestion_item.xml
index 0e2b04f..1fdc1bf 100644
--- a/core/res/res/layout/text_edit_suggestion_item.xml
+++ b/core/res/res/layout/text_edit_suggestion_item.xml
@@ -23,6 +23,7 @@
           android:paddingBottom="8dip"
           android:layout_gravity="left|center_vertical"
           android:singleLine="true"
+          android:drawablePadding="8dip"
           android:ellipsize="marquee"
           android:textAppearance="?android:attr/textAppearanceMedium"
           android:textColor="@android:color/dim_foreground_light" />
diff --git a/docs/html/guide/guide_toc.cs b/docs/html/guide/guide_toc.cs
index 5f74e50..464430b 100644
--- a/docs/html/guide/guide_toc.cs
+++ b/docs/html/guide/guide_toc.cs
@@ -791,7 +791,7 @@
             <span class="en">App Install Location</span>
           </a></li>
       <li><a href="<?cs var:toroot ?>guide/appendix/media-formats.html">
-            <span class="en">Supported Media Formats</span>
+            <span class="en">Supported Media Formats <span class="new">updated</span></span>
           </a></li>
       <li><a href="<?cs var:toroot ?>guide/appendix/g-app-intents.html">
             <span class="en">Intents List: Google Apps</span>
diff --git a/docs/html/guide/practices/ui_guidelines/widget_design.jd b/docs/html/guide/practices/ui_guidelines/widget_design.jd
index f111394..de20e00 100644
--- a/docs/html/guide/practices/ui_guidelines/widget_design.jd
+++ b/docs/html/guide/practices/ui_guidelines/widget_design.jd
@@ -1,4 +1,4 @@
-page.title=Widget Design Guidelines
+page.title=App Widget Design Guidelines
 parent.title=UI Guidelines
 parent.link=index.html
 @jd:body
diff --git a/policy/src/com/android/internal/policy/impl/KeyguardViewMediator.java b/policy/src/com/android/internal/policy/impl/KeyguardViewMediator.java
index 3dae5ad..886997c 100644
--- a/policy/src/com/android/internal/policy/impl/KeyguardViewMediator.java
+++ b/policy/src/com/android/internal/policy/impl/KeyguardViewMediator.java
@@ -31,9 +31,7 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.media.AudioManager;
-import android.media.Ringtone;
-import android.media.RingtoneManager;
-import android.net.Uri;
+import android.media.SoundPool;
 import android.os.Handler;
 import android.os.LocalPowerManager;
 import android.os.Message;
@@ -253,6 +251,11 @@
     private boolean mWaitingUntilKeyguardVisible = false;
     private LockPatternUtils mLockPatternUtils;
 
+    private SoundPool mLockSounds;
+    private int mLockSoundId;
+    private int mUnlockSoundId;
+    private int mLockSoundStreamId;
+
     public KeyguardViewMediator(Context context, PhoneWindowManager callback,
             LocalPowerManager powerManager) {
         mContext = context;
@@ -298,6 +301,22 @@
 
         final ContentResolver cr = mContext.getContentResolver();
         mShowLockIcon = (Settings.System.getInt(cr, "show_status_bar_lock", 0) == 1);
+
+        mLockSounds = new SoundPool(1, AudioManager.STREAM_SYSTEM, 0);
+        String soundPath = Settings.System.getString(cr, Settings.System.LOCK_SOUND);
+        if (soundPath != null) {
+            mLockSoundId = mLockSounds.load(soundPath, 1);
+        }
+        if (soundPath == null || mLockSoundId == 0) {
+            if (DEBUG) Log.d(TAG, "failed to load sound from " + soundPath);
+        }
+        soundPath = Settings.System.getString(cr, Settings.System.UNLOCK_SOUND);
+        if (soundPath != null) {
+            mUnlockSoundId = mLockSounds.load(soundPath, 1);
+        }
+        if (soundPath == null || mUnlockSoundId == 0) {
+            if (DEBUG) Log.d(TAG, "failed to load sound from " + soundPath);
+        }
     }
 
     /**
@@ -1044,29 +1063,11 @@
         final ContentResolver cr = mContext.getContentResolver();
         if (Settings.System.getInt(cr, Settings.System.LOCKSCREEN_SOUNDS_ENABLED, 1) == 1)
         {
-            final String whichSound = locked
-                ? Settings.System.LOCK_SOUND
-                : Settings.System.UNLOCK_SOUND;
-            final String soundPath = Settings.System.getString(cr, whichSound);
-            if (soundPath != null) {
-                final Uri soundUri = Uri.parse("file://" + soundPath);
-                if (soundUri != null) {
-                    final Ringtone sfx = RingtoneManager.getRingtone(mContext, soundUri);
-                    if (sfx != null) {
-                        sfx.setStreamType(AudioManager.STREAM_SYSTEM);
-                        sfx.setWakeMode(mContext, PowerManager.PARTIAL_WAKE_LOCK);
-                        sfx.play();
-                    } else {
-                        if (DEBUG) Log.d(TAG, "playSounds: failed to load ringtone from uri: "
-                                + soundUri);
-                    }
-                } else {
-                    if (DEBUG) Log.d(TAG, "playSounds: could not parse Uri: " + soundPath);
-                }
-            } else {
-                if (DEBUG) Log.d(TAG, "playSounds: whichSound = " + whichSound
-                        + "; soundPath was null");
-            }
+            final int whichSound = locked
+                ? mLockSoundId
+                : mUnlockSoundId;
+            mLockSounds.stop(mLockSoundStreamId);
+            mLockSoundStreamId = mLockSounds.play(whichSound, 1.0f, 1.0f, 1, 0, 1.0f);
         }
     }
 
diff --git a/policy/src/com/android/internal/policy/impl/LockPatternKeyguardView.java b/policy/src/com/android/internal/policy/impl/LockPatternKeyguardView.java
index 2c7f86d..f970ff3 100644
--- a/policy/src/com/android/internal/policy/impl/LockPatternKeyguardView.java
+++ b/policy/src/com/android/internal/policy/impl/LockPatternKeyguardView.java
@@ -996,10 +996,14 @@
     public boolean handleMessage(Message msg) {
         switch (msg.what) {
         case MSG_SHOW_FACELOCK_AREA_VIEW:
-            mFaceLockAreaView.setVisibility(View.VISIBLE);
+            if (mFaceLockAreaView != null) {
+                mFaceLockAreaView.setVisibility(View.VISIBLE);
+            }
             break;
         case MSG_HIDE_FACELOCK_AREA_VIEW:
-            mFaceLockAreaView.setVisibility(View.GONE);
+            if (mFaceLockAreaView != null) {
+                mFaceLockAreaView.setVisibility(View.GONE);
+            }
             break;
         default:
             Log.w(TAG, "Unhandled message");
diff --git a/services/input/EventHub.cpp b/services/input/EventHub.cpp
index 80ee28e..790b395 100644
--- a/services/input/EventHub.cpp
+++ b/services/input/EventHub.cpp
@@ -639,6 +639,8 @@
                         sizeof(struct input_event) * capacity);
                 if (readSize == 0 || (readSize < 0 && errno == ENODEV)) {
                     // Device was removed before INotify noticed.
+                    LOGW("could not get event, removed? (fd: %d size: %d bufferSize: %d capacity: %d errno: %d)\n",
+                         device->fd, readSize, bufferSize, capacity, errno);
                     deviceChanged = true;
                     closeDeviceLocked(device);
                 } else if (readSize < 0) {
@@ -1254,6 +1256,7 @@
             if(event->mask & IN_CREATE) {
                 openDeviceLocked(devname);
             } else {
+                LOGI("Removing device '%s' due to inotify event\n", devname);
                 closeDeviceByPathLocked(devname);
             }
         }
diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java
index 991b7da..8112b1d 100644
--- a/services/java/com/android/server/ConnectivityService.java
+++ b/services/java/com/android/server/ConnectivityService.java
@@ -1975,8 +1975,7 @@
                     Integer pid = (Integer)pids.get(j);
                     if (pid.intValue() == myPid) {
                         Collection<InetAddress> dnses = p.getDnses();
-                        String proto = determineProto(p);
-                        writePidDns(dnses, myPid, proto);
+                        writePidDns(dnses, myPid);
                         if (doBump) {
                             bumpDns();
                         }
@@ -1986,9 +1985,6 @@
            }
         }
         // nothing found - delete
-        if (SystemProperties.get("net.dnsproto." + myPid).length() != 0) {
-            SystemProperties.set("net.dnsproto." + myPid, "");
-        }
         for (int i = 1; ; i++) {
             String prop = "net.dns" + i + "." + myPid;
             if (SystemProperties.get(prop).length() == 0) {
@@ -2002,7 +1998,7 @@
     }
 
     // return true if results in a change
-    private boolean writePidDns(Collection <InetAddress> dnses, int pid, String proto) {
+    private boolean writePidDns(Collection <InetAddress> dnses, int pid) {
         int j = 1;
         boolean changed = false;
         for (InetAddress dns : dnses) {
@@ -2012,11 +2008,6 @@
                 SystemProperties.set("net.dns" + j++ + "." + pid, dns.getHostAddress());
             }
         }
-        if (dnses.size() > 0 && (changed || !proto.equals(SystemProperties.get("net.dnsproto." +
-                pid)))) {
-            changed = true;
-            SystemProperties.set("net.dnsproto." + pid, proto);
-        }
         return changed;
     }
 
@@ -2047,7 +2038,7 @@
 
     // Caller must grab mDnsLock.
     private boolean updateDns(String network, String iface,
-            Collection<InetAddress> dnses, String domains, String proto) {
+            Collection<InetAddress> dnses, String domains) {
         boolean changed = false;
         int last = 0;
         if (dnses.size() == 0 && mDefaultDns != null) {
@@ -2083,11 +2074,6 @@
         }
         mNumDnsEntries = last;
 
-        if (changed || !proto.equals(SystemProperties.get("net.dnsproto"))) {
-            changed = true;
-            SystemProperties.set("net.dnsproto", proto);
-        }
-
         if (changed) {
             try {
                 mNetd.setDnsServersForInterface(iface, NetworkUtils.makeStrings(dnses));
@@ -2111,14 +2097,11 @@
             if (p == null) return;
             Collection<InetAddress> dnses = p.getDnses();
             boolean changed = false;
-            String proto = determineProto(p);
-
             if (mNetConfigs[netType].isDefault()) {
                 String network = nt.getNetworkInfo().getTypeName();
                 synchronized (mDnsLock) {
                     if (!mDnsOverridden) {
-                        changed = updateDns(network, p.getInterfaceName(), dnses, "",
-                                proto);
+                        changed = updateDns(network, p.getInterfaceName(), dnses, "");
                     }
                 }
             } else {
@@ -2132,35 +2115,13 @@
                 List pids = mNetRequestersPids[netType];
                 for (int y=0; y< pids.size(); y++) {
                     Integer pid = (Integer)pids.get(y);
-                    changed = writePidDns(dnses, pid.intValue(), proto);
+                    changed = writePidDns(dnses, pid.intValue());
                 }
             }
             if (changed) bumpDns();
         }
     }
 
-    private String determineProto(LinkProperties p) {
-        boolean v4 = false;
-        boolean v6 = false;
-        for (RouteInfo r : p.getRoutes()) {
-            if (r.getDestination().getAddress() instanceof Inet6Address) {
-                v6 = true;
-            } else {
-                v4 = true;
-            }
-        }
-        // secondary connections often don't have routes and we infer routes
-        // to the dns servers.  Look at the dns addrs too
-        for (InetAddress i : p.getDnses()) {
-            if (i instanceof Inet6Address) {
-                v6 = true;
-            } else {
-                v4 = true;
-            }
-        }
-        return (v4 ? "v4" : "") + (v6 ? "v6" : "");
-    }
-
     private int getRestoreDefaultNetworkDelay(int networkType) {
         String restoreDefaultNetworkDelayStr = SystemProperties.get(
                 NETWORK_RESTORE_DELAY_PROP_NAME);
@@ -2882,7 +2843,7 @@
             // Apply DNS changes.
             boolean changed = false;
             synchronized (mDnsLock) {
-                changed = updateDns("VPN", "VPN", addresses, domains, "v4");
+                changed = updateDns("VPN", "VPN", addresses, domains);
                 mDnsOverridden = true;
             }
             if (changed) {
diff --git a/tools/aapt/Command.cpp b/tools/aapt/Command.cpp
index 178e7fd..413a2dc 100644
--- a/tools/aapt/Command.cpp
+++ b/tools/aapt/Command.cpp
@@ -368,6 +368,7 @@
     REQUIRES_SMALLEST_WIDTH_DP_ATTR = 0x01010364,
     COMPATIBLE_WIDTH_LIMIT_DP_ATTR = 0x01010365,
     LARGEST_WIDTH_LIMIT_DP_ATTR = 0x01010366,
+    PUBLIC_KEY_ATTR = 0x010103a6,
 };
 
 const char *getComponentName(String8 &pkgName, String8 &componentName) {
@@ -1021,6 +1022,15 @@
                     } else if (tag == "compatible-screens") {
                         printCompatibleScreens(tree);
                         depth--;
+                    } else if (tag == "package-verifier") {
+                        String8 name = getAttribute(tree, NAME_ATTR, &error);
+                        if (name != "" && error == "") {
+                            String8 publicKey = getAttribute(tree, PUBLIC_KEY_ATTR, &error);
+                            if (publicKey != "" && error == "") {
+                                printf("package-verifier: name='%s' publicKey='%s'\n",
+                                        name.string(), publicKey.string());
+                            }
+                        }
                     }
                 } else if (depth == 3 && withinApplication) {
                     withinActivity = false;