Merge "Clean up synchronization"
diff --git a/core/java/android/text/TextLine.java b/core/java/android/text/TextLine.java
index b73d900..b3df8ff 100644
--- a/core/java/android/text/TextLine.java
+++ b/core/java/android/text/TextLine.java
@@ -59,6 +59,12 @@
     private boolean mCharsValid;
     private Spanned mSpanned;
     private final TextPaint mWorkPaint = new TextPaint();
+    private final SpanSet<MetricAffectingSpan> mMetricAffectingSpanSpanSet =
+            new SpanSet<MetricAffectingSpan>(MetricAffectingSpan.class);
+    private final SpanSet<CharacterStyle> mCharacterStyleSpanSet =
+            new SpanSet<CharacterStyle>(CharacterStyle.class);
+    private final SpanSet<ReplacementSpan> mReplacementSpanSpanSet =
+            new SpanSet<ReplacementSpan>(ReplacementSpan.class);
 
     private static final TextLine[] sCached = new TextLine[3];
 
@@ -119,7 +125,6 @@
      * @param hasTabs true if the line might contain tabs or emoji
      * @param tabStops the tabStops. Can be null.
      */
-    @SuppressWarnings("null")
     void set(TextPaint paint, CharSequence text, int start, int limit, int dir,
             Directions directions, boolean hasTabs, TabStops tabStops) {
         mPaint = paint;
@@ -135,12 +140,10 @@
         mSpanned = null;
 
         boolean hasReplacement = false;
-        SpanSet<ReplacementSpan> replacementSpans = null;
         if (text instanceof Spanned) {
             mSpanned = (Spanned) text;
-            replacementSpans = new SpanSet<ReplacementSpan>(mSpanned, start, limit,
-                    ReplacementSpan.class);
-            hasReplacement = replacementSpans.numberOfSpans > 0;
+            mReplacementSpanSpanSet.init(mSpanned, start, limit);
+            hasReplacement = mReplacementSpanSpanSet.numberOfSpans > 0;
         }
 
         mCharsValid = hasReplacement || hasTabs || directions != Layout.DIRS_ALL_LEFT_TO_RIGHT;
@@ -158,9 +161,8 @@
                 // zero-width characters.
                 char[] chars = mChars;
                 for (int i = start, inext; i < limit; i = inext) {
-                    // replacementSpans cannot be null if hasReplacement is true
-                    inext = replacementSpans.getNextTransition(i, limit);
-                    if (replacementSpans.hasSpansIntersecting(i, inext)) {
+                    inext = mReplacementSpanSpanSet.getNextTransition(i, limit);
+                    if (mReplacementSpanSpanSet.hasSpansIntersecting(i, inext)) {
                         // transition into a span
                         chars[i - start] = '\ufffc';
                         for (int j = i - start + 1, e = inext - start; j < e; ++j) {
@@ -854,21 +856,30 @@
     }
 
     private static class SpanSet<E> {
-        final int numberOfSpans;
-        final E[] spans;
-        final int[] spanStarts;
-        final int[] spanEnds;
-        final int[] spanFlags;
+        int numberOfSpans;
+        E[] spans;
+        int[] spanStarts;
+        int[] spanEnds;
+        int[] spanFlags;
+        final Class<? extends E> classType;
+
+        SpanSet(Class<? extends E> type) {
+            classType = type;
+            numberOfSpans = 0;
+        }
 
         @SuppressWarnings("unchecked")
-        SpanSet(Spanned spanned, int start, int limit, Class<? extends E> type) {
-            final E[] allSpans = spanned.getSpans(start, limit, type);
+        public void init(Spanned spanned, int start, int limit) {
+            final E[] allSpans = spanned.getSpans(start, limit, classType);
             final int length = allSpans.length;
-            // These arrays may end up being too large because of empty spans
-            spans = (E[]) Array.newInstance(type, length);
-            spanStarts = new int[length];
-            spanEnds = new int[length];
-            spanFlags = new int[length];
+
+            if (length > 0 && (spans == null || spans.length < length)) {
+                // These arrays may end up being too large because of empty spans
+                spans = (E[]) Array.newInstance(classType, length);
+                spanStarts = new int[length];
+                spanEnds = new int[length];
+                spanFlags = new int[length];
+            }
 
             int count = 0;
             for (int i = 0; i < length; i++) {
@@ -879,30 +890,11 @@
                 if (spanStart == spanEnd) continue;
 
                 final int spanFlag = spanned.getSpanFlags(span);
-                final int priority = spanFlag & Spanned.SPAN_PRIORITY;
-                if (priority != 0 && count != 0) {
-                    int j;
 
-                    for (j = 0; j < count; j++) {
-                        final int otherPriority = spanFlags[j] & Spanned.SPAN_PRIORITY;
-                        if (priority > otherPriority) break;
-                    }
-
-                    System.arraycopy(spans, j, spans, j + 1, count - j);
-                    System.arraycopy(spanStarts, j, spanStarts, j + 1, count - j);
-                    System.arraycopy(spanEnds, j, spanEnds, j + 1, count - j);
-                    System.arraycopy(spanFlags, j, spanFlags, j + 1, count - j);
-
-                    spans[j] = span;
-                    spanStarts[j] = spanStart;
-                    spanEnds[j] = spanEnd;
-                    spanFlags[j] = spanFlag;
-                } else {
-                    spans[i] = span;
-                    spanStarts[i] = spanStart;
-                    spanEnds[i] = spanEnd;
-                    spanFlags[i] = spanFlag;
-                }
+                spans[i] = span;
+                spanStarts[i] = spanStart;
+                spanEnds[i] = spanEnd;
+                spanFlags[i] = spanFlag;
 
                 count++;
             }
@@ -970,10 +962,8 @@
                     y, bottom, fmi, needWidth || mlimit < measureLimit);
         }
 
-        final SpanSet<MetricAffectingSpan> metricAffectingSpans = new SpanSet<MetricAffectingSpan>(
-                mSpanned, mStart + start, mStart + limit, MetricAffectingSpan.class);
-        final SpanSet<CharacterStyle> characterStyleSpans = new SpanSet<CharacterStyle>(
-                    mSpanned, mStart + start, mStart + limit, CharacterStyle.class);
+        mMetricAffectingSpanSpanSet.init(mSpanned, mStart + start, mStart + limit);
+        mCharacterStyleSpanSet.init(mSpanned, mStart + start, mStart + limit);
 
         // Shaping needs to take into account context up to metric boundaries,
         // but rendering needs to take into account character style boundaries.
@@ -985,17 +975,18 @@
             TextPaint wp = mWorkPaint;
             wp.set(mPaint);
 
-            inext = metricAffectingSpans.getNextTransition(mStart + i, mStart + limit) - mStart;
+            inext = mMetricAffectingSpanSpanSet.getNextTransition(mStart + i, mStart + limit) -
+                    mStart;
             int mlimit = Math.min(inext, measureLimit);
 
             ReplacementSpan replacement = null;
 
-            for (int j = 0; j < metricAffectingSpans.numberOfSpans; j++) {
+            for (int j = 0; j < mMetricAffectingSpanSpanSet.numberOfSpans; j++) {
                 // Both intervals [spanStarts..spanEnds] and [mStart + i..mStart + mlimit] are NOT
                 // empty by construction. This special case in getSpans() explains the >= & <= tests
-                if ((metricAffectingSpans.spanStarts[j] >= mStart + mlimit) ||
-                        (metricAffectingSpans.spanEnds[j] <= mStart + i)) continue;
-                MetricAffectingSpan span = metricAffectingSpans.spans[j];
+                if ((mMetricAffectingSpanSpanSet.spanStarts[j] >= mStart + mlimit) ||
+                        (mMetricAffectingSpanSpanSet.spanEnds[j] <= mStart + i)) continue;
+                MetricAffectingSpan span = mMetricAffectingSpanSpanSet.spans[j];
                 if (span instanceof ReplacementSpan) {
                     replacement = (ReplacementSpan)span;
                 } else {
@@ -1016,16 +1007,16 @@
                         y, bottom, fmi, needWidth || mlimit < measureLimit);
             } else {
                 for (int j = i, jnext; j < mlimit; j = jnext) {
-                    jnext = characterStyleSpans.getNextTransition(mStart + j, mStart + mlimit) -
+                    jnext = mCharacterStyleSpanSet.getNextTransition(mStart + j, mStart + mlimit) -
                             mStart;
 
                     wp.set(mPaint);
-                    for (int k = 0; k < characterStyleSpans.numberOfSpans; k++) {
+                    for (int k = 0; k < mCharacterStyleSpanSet.numberOfSpans; k++) {
                         // Intentionally using >= and <= as explained above
-                        if ((characterStyleSpans.spanStarts[k] >= mStart + jnext) ||
-                                (characterStyleSpans.spanEnds[k] <= mStart + j)) continue;
+                        if ((mCharacterStyleSpanSet.spanStarts[k] >= mStart + jnext) ||
+                                (mCharacterStyleSpanSet.spanEnds[k] <= mStart + j)) continue;
 
-                        CharacterStyle span = characterStyleSpans.spans[k];
+                        CharacterStyle span = mCharacterStyleSpanSet.spans[k];
                         span.updateDrawState(wp);
                     }
 
diff --git a/core/java/android/text/format/Formatter.java b/core/java/android/text/format/Formatter.java
index 5ae65df..121c6f2 100644
--- a/core/java/android/text/format/Formatter.java
+++ b/core/java/android/text/format/Formatter.java
@@ -21,7 +21,7 @@
 
 /**
  * Utility class to aid in formatting common values that are not covered
- * by {@link java.util.Formatter}
+ * by the {@link java.util.Formatter} class in {@link java.util}
  */
 public final class Formatter {
 
diff --git a/core/java/android/text/format/package.html b/core/java/android/text/format/package.html
new file mode 100644
index 0000000..b9e6a44
--- /dev/null
+++ b/core/java/android/text/format/package.html
@@ -0,0 +1,7 @@
+<HTML>
+<BODY>
+This package contains alternative classes for some text formatting classes
+defined in {@link java.util} and {@link java.text}. It also contains additional text formatting
+classes for situations not covered by {@link java.util} or {@link java.text}.
+</BODY>
+</HTML>
diff --git a/core/java/android/view/VolumePanel.java b/core/java/android/view/VolumePanel.java
index 48fe0df..24a3066 100644
--- a/core/java/android/view/VolumePanel.java
+++ b/core/java/android/view/VolumePanel.java
@@ -400,7 +400,7 @@
         if (LOGD) Log.d(TAG, "onVolumeChanged(streamType: " + streamType + ", flags: " + flags + ")");
 
         if ((flags & AudioManager.FLAG_SHOW_UI) != 0) {
-            if (mActiveStreamType == -1) {
+            if (mActiveStreamType != streamType) {
                 reorderSliders(streamType);
             }
             onShowVolumeChanged(streamType, flags);
diff --git a/core/java/android/webkit/BrowserFrame.java b/core/java/android/webkit/BrowserFrame.java
index c194559..d8f08b2 100644
--- a/core/java/android/webkit/BrowserFrame.java
+++ b/core/java/android/webkit/BrowserFrame.java
@@ -410,6 +410,7 @@
                 mCommitted = false;
                 // remove pending draw to block update until mFirstLayoutDone is
                 // set to true in didFirstLayout()
+                mWebViewCore.clearContent();
                 mWebViewCore.removeMessages(WebViewCore.EventHub.WEBKIT_DRAW);
             }
         }
diff --git a/core/java/android/webkit/WebViewCore.java b/core/java/android/webkit/WebViewCore.java
index 14da23e..de4949c 100644
--- a/core/java/android/webkit/WebViewCore.java
+++ b/core/java/android/webkit/WebViewCore.java
@@ -497,6 +497,13 @@
         message.sendToTarget();
     }
 
+    /**
+     * Clear the picture set. To be called only on the WebCore thread.
+     */
+    /* package */ void clearContent() {
+        nativeClearContent();
+    }
+
     //-------------------------------------------------------------------------
     // JNI methods
     //-------------------------------------------------------------------------
@@ -1560,7 +1567,7 @@
                             // Clear the view so that onDraw() will draw nothing
                             // but white background
                             // (See public method WebView.clearView)
-                            nativeClearContent();
+                            clearContent();
                             break;
 
                         case MESSAGE_RELAY:
diff --git a/core/java/android/widget/SpellChecker.java b/core/java/android/widget/SpellChecker.java
index 31da5b5..6700829 100644
--- a/core/java/android/widget/SpellChecker.java
+++ b/core/java/android/widget/SpellChecker.java
@@ -45,14 +45,15 @@
 
     // No more than this number of words will be parsed on each iteration to ensure a minimum
     // lock of the UI thread
-    public static final int MAX_NUMBER_OF_WORDS = 10;
+    public static final int MAX_NUMBER_OF_WORDS = 50;
 
-    // Safe estimate, will ensure that the interval below usually does not have to be updated
-    public static final int AVERAGE_WORD_LENGTH = 10;
+    // Rough estimate, such that the word iterator interval usually does not need to be shifted
+    public static final int AVERAGE_WORD_LENGTH = 7;
 
     // When parsing, use a character window of that size. Will be shifted if needed
     public static final int WORD_ITERATOR_INTERVAL = AVERAGE_WORD_LENGTH * MAX_NUMBER_OF_WORDS;
 
+    // Pause between each spell check to keep the UI smooth
     private final static int SPELL_PAUSE_DURATION = 400; // milliseconds
 
     private final TextView mTextView;
@@ -75,6 +76,14 @@
 
     private Locale mCurrentLocale;
 
+    // Shared by all SpellParsers. Cannot be shared with TextView since it may be used
+    // concurrently due to the asynchronous nature of onGetSuggestions.
+    private WordIterator mWordIterator;
+
+    private TextServicesManager mTextServicesManager;
+
+    private Runnable mSpellRunnable;
+
     public SpellChecker(TextView textView) {
         mTextView = textView;
 
@@ -136,6 +145,10 @@
         for (int i = 0; i < length; i++) {
             mSpellParsers[i].stop();
         }
+
+        if (mSpellRunnable != null) {
+            mTextView.removeCallbacks(mSpellRunnable);
+        }
     }
 
     private int nextSpellCheckSpanIndex() {
@@ -285,18 +298,29 @@
             }
         }
 
-        mTextView.postDelayed(new Runnable() {
-            @Override
-            public void run() {
-                final int length = mSpellParsers.length;
-                for (int i = 0; i < length; i++) {
-                    final SpellParser spellParser = mSpellParsers[i];
-                    if (spellParser.isParsing()) {
-                        spellParser.parse();
+        scheduleNewSpellCheck();
+    }
+
+    private void scheduleNewSpellCheck() {
+        if (mSpellRunnable == null) {
+            mSpellRunnable = new Runnable() {
+                @Override
+                public void run() {
+                    final int length = mSpellParsers.length;
+                    for (int i = 0; i < length; i++) {
+                        final SpellParser spellParser = mSpellParsers[i];
+                        if (!spellParser.isFinished()) {
+                            spellParser.parse();
+                            break; // run one spell parser at a time to bound running time
+                        }
                     }
                 }
-            }
-        }, SPELL_PAUSE_DURATION);
+            };
+        } else {
+            mTextView.removeCallbacks(mSpellRunnable);
+        }
+
+        mTextView.postDelayed(mSpellRunnable, SPELL_PAUSE_DURATION);
     }
 
     private void createMisspelledSuggestionSpan(Editable editable, SuggestionsInfo suggestionsInfo,
@@ -393,20 +417,19 @@
             final int start = editable.getSpanStart(mRange);
             final int end = editable.getSpanEnd(mRange);
 
-            final WordIterator wordIterator = mTextView.getWordIterator();
             int wordIteratorWindowEnd = Math.min(end, start + WORD_ITERATOR_INTERVAL);
-            wordIterator.setCharSequence(editable, start, wordIteratorWindowEnd);
+            mWordIterator.setCharSequence(editable, start, wordIteratorWindowEnd);
 
             // Move back to the beginning of the current word, if any
-            int wordStart = wordIterator.preceding(start);
+            int wordStart = mWordIterator.preceding(start);
             int wordEnd;
             if (wordStart == BreakIterator.DONE) {
-                wordEnd = wordIterator.following(start);
+                wordEnd = mWordIterator.following(start);
                 if (wordEnd != BreakIterator.DONE) {
-                    wordStart = wordIterator.getBeginning(wordEnd);
+                    wordStart = mWordIterator.getBeginning(wordEnd);
                 }
             } else {
-                wordEnd = wordIterator.getEnd(wordStart);
+                wordEnd = mWordIterator.getEnd(wordStart);
             }
             if (wordEnd == BreakIterator.DONE) {
                 removeRangeSpan(editable);
@@ -472,15 +495,15 @@
 
                 // iterate word by word
                 int originalWordEnd = wordEnd;
-                wordEnd = wordIterator.following(wordEnd);
+                wordEnd = mWordIterator.following(wordEnd);
                 if ((wordIteratorWindowEnd < end) &&
                         (wordEnd == BreakIterator.DONE || wordEnd >= wordIteratorWindowEnd)) {
                     wordIteratorWindowEnd = Math.min(end, originalWordEnd + WORD_ITERATOR_INTERVAL);
-                    wordIterator.setCharSequence(editable, originalWordEnd, wordIteratorWindowEnd);
-                    wordEnd = wordIterator.following(originalWordEnd);
+                    mWordIterator.setCharSequence(editable, originalWordEnd, wordIteratorWindowEnd);
+                    wordEnd = mWordIterator.following(originalWordEnd);
                 }
                 if (wordEnd == BreakIterator.DONE) break;
-                wordStart = wordIterator.getBeginning(wordEnd);
+                wordStart = mWordIterator.getBeginning(wordEnd);
                 if (wordStart == BreakIterator.DONE) {
                     break;
                 }
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 5b73a74..90fb106 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -3210,7 +3210,6 @@
         }
 
         boolean needEditableForNotification = false;
-        boolean startSpellCheck = false;
 
         if (mListeners != null && mListeners.size() != 0) {
             needEditableForNotification = true;
@@ -3222,7 +3221,6 @@
             setFilters(t, mFilters);
             InputMethodManager imm = InputMethodManager.peekInstance();
             if (imm != null) imm.restartInput(this);
-            startSpellCheck = true;
         } else if (type == BufferType.SPANNABLE || mMovement != null) {
             text = mSpannableFactory.newSpannable(text);
         } else if (!(text instanceof CharWrapper)) {
@@ -3311,11 +3309,6 @@
         sendOnTextChanged(text, 0, oldlen, textLength);
         onTextChanged(text, 0, oldlen, textLength);
 
-        if (startSpellCheck && mSpellChecker != null) {
-            // This view has to have been previously attached for mSpellChecker to exist  
-            updateSpellCheckSpans(0, textLength);
-        }
-
         if (needEditableForNotification) {
             sendAfterTextChanged((Editable) text);
         }
@@ -4482,8 +4475,8 @@
 
         // Resolve drawables as the layout direction has been resolved
         resolveDrawables();
-        
-        updateSpellCheckSpans(0, mText.length());
+
+        updateSpellCheckSpans(0, mText.length(), true /* create the spell checker if needed */);
     }
 
     @Override
@@ -7636,7 +7629,7 @@
             }
         }
 
-        updateSpellCheckSpans(start, start + after);
+        updateSpellCheckSpans(start, start + after, false);
 
         // Hide the controllers as soon as text is modified (typing, procedural...)
         // We do not hide the span controllers, since they can be added when a new text is
@@ -7794,17 +7787,22 @@
             }
         }
 
-        if (newStart < 0 && what instanceof SpellCheckSpan) {
-            getSpellChecker().removeSpellCheckSpan((SpellCheckSpan) what);
+        if (mSpellChecker != null && newStart < 0 && what instanceof SpellCheckSpan) {
+            mSpellChecker.removeSpellCheckSpan((SpellCheckSpan) what);
         }
     }
 
     /**
      * Create new SpellCheckSpans on the modified region.
      */
-    private void updateSpellCheckSpans(int start, int end) {
+    private void updateSpellCheckSpans(int start, int end, boolean createSpellChecker) {
         if (isTextEditable() && isSuggestionsEnabled()) {
-            getSpellChecker().spellCheck(start, end);
+            if (mSpellChecker == null && createSpellChecker) {
+                mSpellChecker = new SpellChecker(this);
+            }
+            if (mSpellChecker != null) {
+                mSpellChecker.spellCheck(start, end);
+            }
         }
     }
 
@@ -8976,13 +8974,6 @@
         return packRangeInLong(offset,  offset);
     }
 
-    private SpellChecker getSpellChecker() {
-        if (mSpellChecker == null) {
-            mSpellChecker = new SpellChecker(this);
-        }
-        return mSpellChecker;
-    }
-
     private long getLastTouchOffsets() {
         SelectionModifierCursorController selectionController = getSelectionController();
         final int minOffset = selectionController.getMinTouchOffset();
@@ -9937,7 +9928,7 @@
                 // There is no way to know if the word was indeed added. Re-check.
                 // TODO The ExtractEditText should remove the span in the original text instead
                 editable.removeSpan(suggestionInfo.suggestionSpan);
-                updateSpellCheckSpans(spanStart, spanEnd);
+                updateSpellCheckSpans(spanStart, spanEnd, false);
             } else {
                 // SuggestionSpans are removed by replace: save them before
                 SuggestionSpan[] suggestionSpans = editable.getSpans(spanStart, spanEnd,
diff --git a/core/res/res/layout-sw600dp/keyguard_screen_sim_pin_landscape.xml b/core/res/res/layout-sw600dp/keyguard_screen_sim_pin_landscape.xml
index c65dd83..0b94fc1 100644
--- a/core/res/res/layout-sw600dp/keyguard_screen_sim_pin_landscape.xml
+++ b/core/res/res/layout-sw600dp/keyguard_screen_sim_pin_landscape.xml
@@ -93,17 +93,6 @@
         android:layout_marginLeft="8dip"
         android:layout_marginRight="8dip">
 
-        <Button android:id="@+id/ok"
-            android:text="@android:string/ok"
-            android:layout_alignParentBottom="true"
-            android:layout_width="0dip"
-            android:layout_height="wrap_content"
-            android:layout_weight="1.0"
-            android:layout_marginBottom="8dip"
-            android:layout_marginRight="8dip"
-            android:textSize="18sp"
-            />
-
         <Button android:id="@+id/emergencyCallButton"
             android:text="@android:string/lockscreen_emergency_call"
             android:layout_alignParentBottom="true"
@@ -112,11 +101,22 @@
             android:layout_height="wrap_content"
             android:layout_weight="1.0"
             android:layout_marginBottom="8dip"
-            android:layout_marginLeft="8dip"
+            android:layout_marginRight="8dip"
             android:textSize="18sp"
             android:drawableLeft="@drawable/ic_emergency"
             android:drawablePadding="8dip"
         />
+
+        <Button android:id="@+id/ok"
+            android:text="@android:string/ok"
+            android:layout_alignParentBottom="true"
+            android:layout_width="0dip"
+            android:layout_height="wrap_content"
+            android:layout_weight="1.0"
+            android:layout_marginBottom="8dip"
+            android:layout_marginLeft="8dip"
+            android:textSize="18sp"
+        />
     </LinearLayout>
 
 </RelativeLayout>
diff --git a/core/res/res/layout/keyguard_screen_sim_pin_landscape.xml b/core/res/res/layout/keyguard_screen_sim_pin_landscape.xml
index 59065e1..3cb19c3 100644
--- a/core/res/res/layout/keyguard_screen_sim_pin_landscape.xml
+++ b/core/res/res/layout/keyguard_screen_sim_pin_landscape.xml
@@ -91,17 +91,6 @@
         android:layout_marginLeft="8dip"
         android:layout_marginRight="8dip">
 
-        <Button android:id="@+id/ok"
-            android:text="@android:string/ok"
-            android:layout_alignParentBottom="true"
-            android:layout_width="0dip"
-            android:layout_height="wrap_content"
-            android:layout_weight="1.0"
-            android:layout_marginBottom="8dip"
-            android:layout_marginRight="8dip"
-            android:textSize="18sp"
-            />
-
         <Button android:id="@+id/emergencyCallButton"
             android:text="@android:string/lockscreen_emergency_call"
             android:layout_alignParentBottom="true"
@@ -110,11 +99,22 @@
             android:layout_height="wrap_content"
             android:layout_weight="1.0"
             android:layout_marginBottom="8dip"
-            android:layout_marginLeft="8dip"
+            android:layout_marginRight="8dip"
             android:textSize="18sp"
             android:drawableLeft="@drawable/ic_emergency"
             android:drawablePadding="4dip"
         />
+
+        <Button android:id="@+id/ok"
+            android:text="@android:string/ok"
+            android:layout_alignParentBottom="true"
+            android:layout_width="0dip"
+            android:layout_height="wrap_content"
+            android:layout_weight="1.0"
+            android:layout_marginBottom="8dip"
+            android:layout_marginLeft="8dip"
+            android:textSize="18sp"
+        />
     </LinearLayout>
 
 </RelativeLayout>
diff --git a/core/res/res/layout/keyguard_screen_sim_puk_landscape.xml b/core/res/res/layout/keyguard_screen_sim_puk_landscape.xml
index b662e82..722dc26 100644
--- a/core/res/res/layout/keyguard_screen_sim_puk_landscape.xml
+++ b/core/res/res/layout/keyguard_screen_sim_puk_landscape.xml
@@ -153,17 +153,6 @@
         android:layout_marginLeft="8dip"
         android:layout_marginRight="8dip">
 
-        <Button android:id="@+id/ok"
-            android:text="@android:string/ok"
-            android:layout_alignParentBottom="true"
-            android:layout_width="0dip"
-            android:layout_height="wrap_content"
-            android:layout_weight="1.0"
-            android:layout_marginBottom="8dip"
-            android:layout_marginRight="8dip"
-            android:textSize="18sp"
-            />
-
         <Button android:id="@+id/emergencyCallButton"
             android:text="@android:string/lockscreen_emergency_call"
             android:layout_alignParentBottom="true"
@@ -172,11 +161,22 @@
             android:layout_height="wrap_content"
             android:layout_weight="1.0"
             android:layout_marginBottom="8dip"
-            android:layout_marginLeft="8dip"
+            android:layout_marginRight="8dip"
             android:textSize="18sp"
             android:drawableLeft="@drawable/ic_emergency"
             android:drawablePadding="4dip"
         />
+
+        <Button android:id="@+id/ok"
+            android:text="@android:string/ok"
+            android:layout_alignParentBottom="true"
+            android:layout_width="0dip"
+            android:layout_height="wrap_content"
+            android:layout_weight="1.0"
+            android:layout_marginBottom="8dip"
+            android:layout_marginLeft="8dip"
+            android:textSize="18sp"
+        />
     </LinearLayout>
 
 </RelativeLayout>
diff --git a/core/res/res/layout/twelve_key_entry.xml b/core/res/res/layout/twelve_key_entry.xml
index 46301cd..09c749d 100644
--- a/core/res/res/layout/twelve_key_entry.xml
+++ b/core/res/res/layout/twelve_key_entry.xml
@@ -144,7 +144,7 @@
         android:layout_marginRight="2dip"
         android:orientation="horizontal">
 
-        <Button android:id="@+id/ok"
+        <Button android:id="@+id/cancel"
             android:layout_width="0sp"
             android:layout_height="fill_parent"
             android:layout_weight="1"
@@ -152,7 +152,7 @@
             android:layout_marginRight="2dip"
             android:textAppearance="?android:attr/textAppearanceMedium"
             android:textStyle="bold"
-            android:text="@android:string/ok"
+            android:text="@android:string/cancel"
         />
 
         <Button android:id="@+id/zero"
@@ -165,7 +165,7 @@
             android:textStyle="bold"
         />
 
-        <Button android:id="@+id/cancel"
+        <Button android:id="@+id/ok"
             android:layout_width="0sp"
             android:layout_height="fill_parent"
             android:layout_weight="1"
@@ -173,7 +173,7 @@
             android:layout_marginRight="2dip"
             android:textAppearance="?android:attr/textAppearanceMedium"
             android:textStyle="bold"
-            android:text="@android:string/cancel"
+            android:text="@android:string/ok"
         />
 
     </LinearLayout>
diff --git a/docs/html/sdk/android-4.0.jd b/docs/html/sdk/android-4.0.jd
index e886bdf..7161b03 100644
--- a/docs/html/sdk/android-4.0.jd
+++ b/docs/html/sdk/android-4.0.jd
@@ -65,26 +65,42 @@
 <p>To determine what revision of the Android {@sdkPlatformVersion} platform you
 have installed, refer to the "Installed Packages" listing in the Android SDK Manager.</p>
 
+<p class="caution"><strong>Important:</strong> To download the new Android
+4.0 system components from the Android SDK Manager, you must first update the
+SDK tools to revision 14 or later and restart the Android SDK Manager. If you do not,
+the Android 4.0 system components will not be available for download.</p>
 
 <div class="toggle-content opened" style="padding-left:1em;">
 
   <p><a href="#" onclick="return toggleContent(this)">
     <img src="{@docRoot}assets/images/triangle-opened.png"
 class="toggle-content-img" alt="" />
+    Android {@sdkPlatformVersion}, Revision 2</a> <em>(December 2011)</em>
+  </a></p>
+
+  <div class="toggle-content-toggleme" style="padding-left:2em;">
+    <p>Maintenance update. The system version is 4.0.2.</p>
+    <dl>
+      <dt>Dependencies:</dt>
+      <dd>SDK Tools r14 or higher is required.</dd>
+    </dl>
+  </div>
+</div>
+
+<div class="toggle-content closed" style="padding-left:1em;">
+
+  <p><a href="#" onclick="return toggleContent(this)">
+    <img src="{@docRoot}assets/images/triangle-closed.png"
+class="toggle-content-img" alt="" />
     Android {@sdkPlatformVersion}, Revision 1</a> <em>(October 2011)</em>
   </a></p>
 
   <div class="toggle-content-toggleme" style="padding-left:2em;">
-
-<dl>
-<dt>Initial release. SDK Tools r14 or higher is required.
-  <p class="caution"><strong>Important:</strong> To download the new Android
-  4.0 system components from the Android SDK Manager, you must first update the
-  SDK tools to revision 14 or later and restart the Android SDK Manager. If you do not,
-  the Android 4.0 system components will not be available for download.</p>
-</dt>
-</dl>
-
+    <p>Initial release. The system version is 4.0.1.</p>
+    <dl>
+      <dt>Dependencies:</dt>
+      <dd>SDK Tools r14 or higher is required.</dd>
+    </dl>
   </div>
 </div>
 
diff --git a/docs/html/sdk/eclipse-adt.jd b/docs/html/sdk/eclipse-adt.jd
index 50b20ce..2445bff 100644
--- a/docs/html/sdk/eclipse-adt.jd
+++ b/docs/html/sdk/eclipse-adt.jd
@@ -1,8 +1,8 @@
 page.title=ADT Plugin for Eclipse
-adt.zip.version=15.0.1
-adt.zip.download=ADT-15.0.1.zip
-adt.zip.bytes=6752327
-adt.zip.checksum=2c12a71d7124aa512b8ee016e19c0e69
+adt.zip.version=16.0.0
+adt.zip.download=ADT-16.0.0.zip
+adt.zip.bytes=6999205
+adt.zip.checksum=b7e512572580291279469845386b31b6
 
 @jd:body
 
@@ -109,18 +109,49 @@
 </style>
 
 
-
 <div class="toggleable opened">
   <a href="#" onclick="return toggleDiv(this)">
         <img src="{@docRoot}assets/images/triangle-opened.png" class="toggle-img" height="9px"
 width="9px" />
+ADT 16.0.0</a> <em>(December 2011)</em>
+  <div class="toggleme">
+<dl>
+  <dt>Dependencies:</dt>
+
+  <dd>
+    <ul>
+      <li>Eclipse Helios (Version 3.6) or higher is required for ADT
+16.0.0.</li>
+      <li>ADT 16.0.0 is designed for use with <a
+href="{@docRoot}sdk/tools-notes.html">SDK Tools r16</a>. If you haven't already installed SDK Tools
+r16 into your SDK, use the Android SDK Manager to do so.</li>
+    </ul>
+  </dd>
+
+  <dt>General improvements:</dt>
+  <dd>
+    <ul>
+      <li>Added Lint tools to detect common errors in Android projects. (<a
+href="http://tools.android.com/recent/lint">more info</a>)</li>
+    </ul>
+  </dd>
+</dl>
+
+</div>
+</div>
+
+
+<div class="toggleable closed">
+  <a href="#" onclick="return toggleDiv(this)">
+        <img src="{@docRoot}assets/images/triangle-closed.png" class="toggle-img" height="9px"
+width="9px" />
 ADT 15.0.1</a> <em>(November 2011)</em>
   <div class="toggleme">
 <dl>
   <dt>Dependencies:</dt>
   
   <dd>ADT 15.0.1 is designed for use with <a href="{@docRoot}sdk/tools-notes.html">SDK Tools r15</a>.
-  If you haven't already installed SDK Tools r15 into your SDK, use the Android SDK and AVD Manager to
+  If you haven't already installed SDK Tools r15 into your SDK, use the Android SDK Manager to
   do so.</dd>
   
   <dt>Bug fixes:</dt>
@@ -154,7 +185,7 @@
 <dt>Dependencies:</dt>
 
 <dd>ADT 15.0.0 is designed for use with <a href="{@docRoot}sdk/tools-notes.html">SDK Tools r15</a>.
-If you haven't already installed SDK Tools r15 into your SDK, use the Android SDK and AVD Manager to
+If you haven't already installed SDK Tools r15 into your SDK, use the Android SDK Manager to
 do so.</dd>
 
 <dt>Bug fixes:</dt>
@@ -185,10 +216,10 @@
 <dt>Dependencies:</dt>
 
 <dd>ADT 14.0.0 is designed for use with <a href="{@docRoot}sdk/tools-notes.html">SDK Tools r14</a>.
-If you haven't already installed SDK Tools r14 into your SDK, use the Android SDK and AVD Manager to
+If you haven't already installed SDK Tools r14 into your SDK, use the Android SDK Manager to
 do so.</dd>
 
-<dt>Build system</dt>
+<dt>Build system:</dt>
 <dd>
   <ul>
     <li>Changed <code>default.properties</code> to <code>project.properties</code> and
@@ -211,7 +242,7 @@
 site</a>.</p>
 </dd>
 
-<dt>General improvements</dt>
+<dt>General improvements:</dt>
 <dd>
   <ul>
 
@@ -236,7 +267,7 @@
 </ul>
 </dd>
 
-<dt>XML and Java editors</dt>
+<dt>XML and Java editors:</dt>
 <dd>
   <ul>
     <li>Added a new XML formatter that formats all XML files according to the
@@ -255,7 +286,7 @@
   </ul>
 </dd>
 
-<dt>Layout editor</dt>
+<dt>Layout editor:</dt>
 <dd>
   <ul>
     <li>Added tooltip feedback for dragging and resizing operations. For
@@ -281,7 +312,7 @@
   </ul>
 </dd>
 
-<dt>Bug fixes</dt>
+<dt>Bug fixes:</dt>
 <dd>Fixed many bugs and added <a
 href="http://tools.android.com/recent/miscellaneousrecentfixes">minor improvements</a>, in
 particular some <a href="http://tools.android.com/recent/linuxfixes">critical bug fixes on
@@ -324,7 +355,7 @@
 </ul>
 </dd>
 
-<dt>Build system</dt>
+<dt>Build system:</dt>
 <dd>
 <ul>
   <li id="build-option">A new option lets you disable the packaging step in the automatic
@@ -336,7 +367,7 @@
 </ul>
 </dd>
 
-<dt>Bug fixes</dt>
+<dt>Bug fixes:</dt>
 <dd>Many bug fixes are part of this release
 (<a href="http://tools.android.com/recent/adt12bugfixroundup">more info</a>).</dd>
 
@@ -928,7 +959,7 @@
 see <a href="{@docRoot}sdk/adding-components.html">Adding SDK Components</a>.</p>
 </dd>
 
-<dt>General Notes:</dt>
+<dt>General notes:</dt>
 <dd>
 <ul>
 <li>AVD Launch dialog now shows scale value.</li>
@@ -974,7 +1005,7 @@
 </ul>
 </dd>
 
-<dt>DDMS Integration:</dt>
+<dt>DDMS integration:</dt>
 <dd>
 <ul>
 <li>Includes the improvements from the standlone DDMS, revision 3.</li>
diff --git a/docs/html/sdk/index.jd b/docs/html/sdk/index.jd
index 193066b..65a1f46 100644
--- a/docs/html/sdk/index.jd
+++ b/docs/html/sdk/index.jd
@@ -1,21 +1,21 @@
 page.title=Android SDK
 sdk.redirect=0
 
-sdk.win_installer=installer_r15-windows.exe
-sdk.win_installer_bytes=33902520
-sdk.win_installer_checksum=ee8481cb86a6646a4d963d5142902c5c
+sdk.win_installer=installer_r16-windows.exe
+sdk.win_installer_bytes=29561554
+sdk.win_installer_checksum=3521dda4904886b05980590f83cf3469
 
-sdk.win_download=android-sdk_r15-windows.zip
-sdk.win_bytes=33895447
-sdk.win_checksum=cc2aadf7120d12b574981461736a96e9
+sdk.win_download=android-sdk_r16-windows.zip
+sdk.win_bytes=29562413
+sdk.win_checksum=6b926d0c0a871f1a946e65259984701a
 
-sdk.mac_download=android-sdk_r15-macosx.zip
-sdk.mac_bytes=30469921
-sdk.mac_checksum=03d2cdd3565771e8c7a438f1c40cc8a5
+sdk.mac_download=android-sdk_r16-macosx.zip
+sdk.mac_bytes=26158334
+sdk.mac_checksum=d1dc2b6f13eed5e3ce5cf26c4e4c47aa
 
-sdk.linux_download=android-sdk_r15-linux.tgz
-sdk.linux_bytes=26124434
-sdk.linux_checksum=f529681fd1eda11c6e1e1d44b42c1432
+sdk.linux_download=android-sdk_r16-linux.tgz
+sdk.linux_bytes=22048174
+sdk.linux_checksum=3ba457f731d51da3741c29c8830a4583
 
 @jd:body
 
diff --git a/docs/html/sdk/requirements.jd b/docs/html/sdk/requirements.jd
index f12d0aa..c970f6c 100644
--- a/docs/html/sdk/requirements.jd
+++ b/docs/html/sdk/requirements.jd
@@ -24,8 +24,8 @@
 
 <h4 style="margin-top:.25em"><em>Eclipse IDE</em></h4>
     <ul>
-      <li>Eclipse 3.5 (Galileo) or greater 
-<p class="note"><strong>Note:</strong> Eclipse 3.4 (Ganymede) is no longer
+      <li>Eclipse 3.6 (Helios) or greater
+<p class="note"><strong>Note:</strong> Eclipse 3.5 (Galileo) is no longer
 supported with the latest version of ADT.</p></li>
       <li>Eclipse <a href="http://www.eclipse.org/jdt">JDT</a> plugin (included
 in most Eclipse IDE packages) </li>
@@ -37,7 +37,7 @@
 packages: </p>
          <ul>
            <li>Eclipse IDE for Java Developers</li>
-           <li>Eclipse Classic (versions 3.5.1 and higher)</li>
+           <li>Eclipse Classic</li>
            <li>Eclipse IDE for Java EE Developers</li>
          </ul>
       </li>
diff --git a/docs/html/sdk/sdk_toc.cs b/docs/html/sdk/sdk_toc.cs
index 0ae2c6d..791e7aa 100644
--- a/docs/html/sdk/sdk_toc.cs
+++ b/docs/html/sdk/sdk_toc.cs
@@ -150,7 +150,7 @@
       </li>
     </ul>
     <ul>
-      <li><a href="<?cs var:toroot ?>sdk/tools-notes.html">SDK Tools, r15</a> <span
+      <li><a href="<?cs var:toroot ?>sdk/tools-notes.html">SDK Tools, r16</a> <span
 class="new">new!</span></li>
       <li><a href="<?cs var:toroot ?>sdk/win-usb.html">Google USB Driver, r4</a></li>
       <li><a href="<?cs var:toroot ?>sdk/compatibility-library.html">Support Package, r4</a>
@@ -169,7 +169,7 @@
       <span style="display:none" class="zh-TW"></span>
       </h2>
     <ul>
-      <li><a href="<?cs var:toroot ?>sdk/eclipse-adt.html">ADT 15.0.1
+      <li><a href="<?cs var:toroot ?>sdk/eclipse-adt.html">ADT 16.0.0
       <span style="display:none" class="de"></span>
       <span style="display:none" class="es"></span>
       <span style="display:none" class="fr"></span>
diff --git a/docs/html/sdk/tools-notes.jd b/docs/html/sdk/tools-notes.jd
index cd03d9f..9a63467 100644
--- a/docs/html/sdk/tools-notes.jd
+++ b/docs/html/sdk/tools-notes.jd
@@ -9,7 +9,7 @@
 latest revision of the SDK Tools in the <code>&lt;sdk&gt;/tools</code> directory.</p>
 
 <p>If you are already using the SDK and you want to update to the latest version
-of the SDK Tools, use the <em>Android SDK and AVD Manager</em> to get the
+of the SDK Tools, use the <em>Android SDK Manager</em> to get the
 update, rather than downloading a new SDK starter package. For more information
 about how to update, see <a
 href="{@docRoot}sdk/adding-components.html#UpdatingComponents">Updating SDK
@@ -20,8 +20,7 @@
 
 <p>The sections below provide notes about successive releases of
 the SDK Tools, as denoted by revision number. To determine what revision of the SDK
-Tools you are using, refer to the "Installed Packages" listing in the Android SDK
-and AVD Manager. </p>
+Tools you are using, refer to the "Installed Packages" listing in the Android SDK Manager. </p>
 
 <p>For a summary of all known issues in SDK Tools, see <a
 href="http://tools.android.com/knownissues">http://tools.android.com/knownissues</a>.</p>
@@ -69,7 +68,57 @@
 <div class="toggleable opened">
   <a href="#" onclick="return toggleDiv(this)">
     <img src="{@docRoot}assets/images/triangle-opened.png" class="toggle-img" height="9px"
-    width="9px" />SDK Tools, Revision 15</a> <em>(October 2011)</em>
+    width="9px" />
+    SDK Tools, Revision 16</a> <em>(December 2011)</em>
+
+  <div class="toggleme">
+    <p class="caution"><strong>Important:</strong> To download the new Android
+    4.0 system components from the Android SDK Manager, you must first update the
+    SDK tools to revision 14 or later and restart the Android SDK Manager. If you do not,
+    the Android 4.0 system components will not be available for download.</p>
+
+<dl>
+<dt>Dependencies:</dt>
+<dd>
+  <ul>
+    <li>Android SDK Platform-tools revision 9 or later.</li>
+    <li>If you are developing in Eclipse with ADT, note that the SDK Tools r16 is designed for use
+    with ADT 16.0.0 and later. If you haven't already, we highly recommend updating your
+    <a href="{@docRoot}sdk/eclipse-adt.html">ADT Plugin</a> to 16.0.0.</li>
+    <li>If you are developing outside Eclipse, you must have <a href="http://ant.apache.org/">Apache
+    Ant</a> 1.8 or later.</li>
+</ul>
+</dd>
+<dt>General notes:</dt>
+<dd>
+  <ul>
+    <li>Added Lint tools to detect common errors in Android projects. (<a
+href="http://tools.android.com/recent/lint">more info</a>)</li>
+    <li>Added sensor emulation support, which allows the emulator to read sensor data from a
+physical Android device.</li>
+    <li>Added support for using a webcam to emulate a camera on Mac OS X.</li>
+  </ul>
+</dd>
+<dt>Bug fixes:</dt>
+<dd>
+  <ul>
+    <li>Snapshots now work for Android 4.0 system images.</li>
+    <li>Fixed several small issues for the build file.
+    (<a href="http://code.google.com/p/android/issues/detail?id=21023">Issue 21023</a>,
+    <a href="http://code.google.com/p/android/issues/detail?id=21267">Issue 21267</a>,
+    <a href="http://code.google.com/p/android/issues/detail?id=21465">Issue 21465</a>,
+    <a href="http://code.google.com/p/android/issues/detail?id=21525">Issue 21525</a>).</li>
+  </ul>
+</dd>
+</dl>
+</div>
+</div>
+
+<div class="toggleable closed">
+  <a href="#" onclick="return toggleDiv(this)">
+    <img src="{@docRoot}assets/images/triangle-closed.png" class="toggle-img" height="9px"
+    width="9px" />
+    SDK Tools, Revision 15</a> <em>(October 2011)</em>
 
   <div class="toggleme">
     <p class="caution"><strong>Important:</strong> To download the new Android
@@ -116,7 +165,8 @@
 <div class="toggleable closed">
   <a href="#" onclick="return toggleDiv(this)">
     <img src="{@docRoot}assets/images/triangle-closed.png" class="toggle-img" height="9px"
-    width="9px" />SDK Tools, Revision 14</a> <em>(October 2011)</em>
+    width="9px" />
+    SDK Tools, Revision 14</a> <em>(October 2011)</em>
 
   <div class="toggleme">
     <p class="note"><strong>Important:</strong> To download the new Android
@@ -137,10 +187,11 @@
 <dt>General notes:</dt>
 <dd>
   <ul>
-    <li>Added webcam support to Android 4.0 or later platforms to emulate rear-facing cameras when one webcam is present,
-    and to emulate both rear-facing and front-facing cameras when two webcams are present. Webcam suport is for Windows and Linux only.
+    <li>Added webcam support to Android 4.0 or later platforms to emulate rear-facing cameras when
+    one webcam is present, and to emulate both rear-facing and front-facing cameras when two
+    webcams are present. Webcam support is for Windows and Linux only.
     Mac support will come in a later release.</li>
-     <li>Changed <code>default.properties</code> to <code>project.properties</code> and
+    <li>Changed <code>default.properties</code> to <code>project.properties</code> and
     <code>build.properties</code> to <code>ant.properties</code>. Any existing
     projects that you build with Ant must be updated with the <code>android update project</code>
     command.</li>
@@ -428,7 +479,7 @@
 for more information.</li>
 <li>Fixes location control in DDMS to work in any locale not using '.' as a
 decimal point.</li>
-</li>
+</ul>
 </ul>
 </dd>
 </dl>
diff --git a/libs/hwui/Program.cpp b/libs/hwui/Program.cpp
index 972dd87..4aff23e 100644
--- a/libs/hwui/Program.cpp
+++ b/libs/hwui/Program.cpp
@@ -27,35 +27,47 @@
 
 Program::Program(const char* vertex, const char* fragment) {
     mInitialized = false;
+    mHasColorUniform = false;
 
-    vertexShader = buildShader(vertex, GL_VERTEX_SHADER);
+    // No need to cache compiled shaders, rely instead on Android's
+    // persistent shaders cache
+    GLuint vertexShader = buildShader(vertex, GL_VERTEX_SHADER);
     if (vertexShader) {
 
-        fragmentShader = buildShader(fragment, GL_FRAGMENT_SHADER);
+        GLuint fragmentShader = buildShader(fragment, GL_FRAGMENT_SHADER);
         if (fragmentShader) {
 
-            id = glCreateProgram();
-            glAttachShader(id, vertexShader);
-            glAttachShader(id, fragmentShader);
-            glLinkProgram(id);
+            mProgramId = glCreateProgram();
+            glAttachShader(mProgramId, vertexShader);
+            glAttachShader(mProgramId, fragmentShader);
+            glLinkProgram(mProgramId);
 
             GLint status;
-            glGetProgramiv(id, GL_LINK_STATUS, &status);
+            glGetProgramiv(mProgramId, GL_LINK_STATUS, &status);
             if (status != GL_TRUE) {
                 LOGE("Error while linking shaders:");
                 GLint infoLen = 0;
-                glGetProgramiv(id, GL_INFO_LOG_LENGTH, &infoLen);
+                glGetProgramiv(mProgramId, GL_INFO_LOG_LENGTH, &infoLen);
                 if (infoLen > 1) {
                     GLchar log[infoLen];
-                    glGetProgramInfoLog(id, infoLen, 0, &log[0]);
+                    glGetProgramInfoLog(mProgramId, infoLen, 0, &log[0]);
                     LOGE("%s", log);
                 }
-                glDeleteShader(vertexShader);
-                glDeleteShader(fragmentShader);
-                glDeleteProgram(id);
             } else {
                 mInitialized = true;
             }
+
+            glDetachShader(mProgramId, vertexShader);
+            glDetachShader(mProgramId, fragmentShader);
+
+            glDeleteShader(vertexShader);
+            glDeleteShader(fragmentShader);
+
+            if (!mInitialized) {
+                glDeleteProgram(mProgramId);
+            }
+        } else {
+            glDeleteShader(vertexShader);
         }
     }
 
@@ -69,36 +81,34 @@
 
 Program::~Program() {
     if (mInitialized) {
-        glDeleteShader(vertexShader);
-        glDeleteShader(fragmentShader);
-        glDeleteProgram(id);
+        glDeleteProgram(mProgramId);
     }
 }
 
 int Program::addAttrib(const char* name) {
-    int slot = glGetAttribLocation(id, name);
-    attributes.add(name, slot);
+    int slot = glGetAttribLocation(mProgramId, name);
+    mAttributes.add(name, slot);
     return slot;
 }
 
 int Program::getAttrib(const char* name) {
-    ssize_t index = attributes.indexOfKey(name);
+    ssize_t index = mAttributes.indexOfKey(name);
     if (index >= 0) {
-        return attributes.valueAt(index);
+        return mAttributes.valueAt(index);
     }
     return addAttrib(name);
 }
 
 int Program::addUniform(const char* name) {
-    int slot = glGetUniformLocation(id, name);
-    uniforms.add(name, slot);
+    int slot = glGetUniformLocation(mProgramId, name);
+    mUniforms.add(name, slot);
     return slot;
 }
 
 int Program::getUniform(const char* name) {
-    ssize_t index = uniforms.indexOfKey(name);
+    ssize_t index = mUniforms.indexOfKey(name);
     if (index >= 0) {
-        return uniforms.valueAt(index);
+        return mUniforms.valueAt(index);
     }
     return addUniform(name);
 }
@@ -127,10 +137,11 @@
         const mat4& transformMatrix, bool offset) {
     mat4 t(projectionMatrix);
     if (offset) {
-        // offset screenspace xy by an amount that compensates for typical precision issues
-        // in GPU hardware that tends to paint hor/vert lines in pixels shifted up and to the left.
-        // This offset value is based on an assumption that some hardware may use as little
-        // as 12.4 precision, so we offset by slightly more than 1/16.
+        // offset screenspace xy by an amount that compensates for typical precision
+        // issues in GPU hardware that tends to paint hor/vert lines in pixels shifted
+        // up and to the left.
+        // This offset value is based on an assumption that some hardware may use as
+        // little as 12.4 precision, so we offset by slightly more than 1/16.
         t.translate(.375, .375, 0);
     }
     t.multiply(transformMatrix);
@@ -140,20 +151,24 @@
 }
 
 void Program::setColor(const float r, const float g, const float b, const float a) {
-    glUniform4f(getUniform("color"), r, g, b, a);
+    if (!mHasColorUniform) {
+        mColorUniform = getUniform("color");
+        mHasColorUniform = true;
+    }
+    glUniform4f(mColorUniform, r, g, b, a);
 }
 
 void Program::use() {
-    glUseProgram(id);
+    glUseProgram(mProgramId);
     mUse = true;
-
     glEnableVertexAttribArray(position);
 }
 
 void Program::remove() {
     mUse = false;
-
-    glDisableVertexAttribArray(position);
+    // TODO: Is this necessary? It should not be since all of our shaders
+    //       use slot 0 for the position attrib
+    // glDisableVertexAttribArray(position);
 }
 
 }; // namespace uirenderer
diff --git a/libs/hwui/Program.h b/libs/hwui/Program.h
index 764cb05..edd1209 100644
--- a/libs/hwui/Program.h
+++ b/libs/hwui/Program.h
@@ -122,18 +122,17 @@
     GLuint buildShader(const char* source, GLenum type);
 
     // Name of the OpenGL program
-    GLuint id;
-
-    // Name of the shaders
-    GLuint vertexShader;
-    GLuint fragmentShader;
+    GLuint mProgramId;
 
     // Keeps track of attributes and uniforms slots
-    KeyedVector<const char*, int> attributes;
-    KeyedVector<const char*, int> uniforms;
+    KeyedVector<const char*, int> mAttributes;
+    KeyedVector<const char*, int> mUniforms;
 
     bool mUse;
     bool mInitialized;
+
+    bool mHasColorUniform;
+    int mColorUniform;
 }; // class Program
 
 }; // namespace uirenderer
diff --git a/libs/hwui/ProgramCache.h b/libs/hwui/ProgramCache.h
index 5c7197b..441db8c 100644
--- a/libs/hwui/ProgramCache.h
+++ b/libs/hwui/ProgramCache.h
@@ -27,6 +27,7 @@
 
 #include "Debug.h"
 #include "Program.h"
+#include "Properties.h"
 
 namespace android {
 namespace uirenderer {
@@ -42,8 +43,6 @@
     #define PROGRAM_LOGD(...)
 #endif
 
-// TODO: This should be set in properties
-#define PANEL_BIT_DEPTH 20
 #define COLOR_COMPONENT_THRESHOLD (1.0f - (0.5f / PANEL_BIT_DEPTH))
 #define COLOR_COMPONENT_INV_THRESHOLD (0.5f / PANEL_BIT_DEPTH)
 
diff --git a/libs/hwui/Properties.h b/libs/hwui/Properties.h
index 8c01e3a..2eae0f1 100644
--- a/libs/hwui/Properties.h
+++ b/libs/hwui/Properties.h
@@ -73,6 +73,9 @@
 #define PROPERTY_TEXT_BLACK_GAMMA_THRESHOLD "ro.text_gamma.black_threshold"
 #define PROPERTY_TEXT_WHITE_GAMMA_THRESHOLD "ro.text_gamma.white_threshold"
 
+// TODO: This should be set by a system property
+#define PANEL_BIT_DEPTH 20
+
 // Converts a number of mega-bytes into bytes
 #define MB(s) s * 1024 * 1024
 
diff --git a/media/libmediaplayerservice/nuplayer/RTSPSource.cpp b/media/libmediaplayerservice/nuplayer/RTSPSource.cpp
index a3f2bf6..6d28298 100644
--- a/media/libmediaplayerservice/nuplayer/RTSPSource.cpp
+++ b/media/libmediaplayerservice/nuplayer/RTSPSource.cpp
@@ -242,7 +242,7 @@
                     // playtime mapping. Assume the first packets correspond
                     // to time 0.
 
-                    LOGV("This is a live stream, assuming time = 0");
+                    ALOGV("This is a live stream, assuming time = 0");
 
                     info->mRTPTime = rtpTime;
                     info->mNormalPlaytimeUs = 0ll;
diff --git a/media/libstagefright/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp
index 8405264..42f18d3 100644
--- a/media/libstagefright/AwesomePlayer.cpp
+++ b/media/libstagefright/AwesomePlayer.cpp
@@ -335,11 +335,13 @@
         return UNKNOWN_ERROR;
     }
 
-    dataSource->getDrmInfo(mDecryptHandle, &mDrmManagerClient);
-    if (mDecryptHandle != NULL) {
-        CHECK(mDrmManagerClient);
-        if (RightsStatus::RIGHTS_VALID != mDecryptHandle->status) {
-            notifyListener_l(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, ERROR_DRM_NO_LICENSE);
+    if (extractor->getDrmFlag()) {
+        dataSource->getDrmInfo(mDecryptHandle, &mDrmManagerClient);
+        if (mDecryptHandle != NULL) {
+            CHECK(mDrmManagerClient);
+            if (RightsStatus::RIGHTS_VALID != mDecryptHandle->status) {
+                notifyListener_l(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, ERROR_DRM_NO_LICENSE);
+            }
         }
     }
 
@@ -2103,6 +2105,7 @@
 
         mWVMExtractor = new WVMExtractor(dataSource);
         mWVMExtractor->setAdaptiveStreamingMode(true);
+        mWVMExtractor->setDrmFlag(true);
         extractor = mWVMExtractor;
     } else {
         extractor = MediaExtractor::Create(
@@ -2113,12 +2116,14 @@
         }
     }
 
-    dataSource->getDrmInfo(mDecryptHandle, &mDrmManagerClient);
+    if (extractor->getDrmFlag()) {
+        dataSource->getDrmInfo(mDecryptHandle, &mDrmManagerClient);
 
-    if (mDecryptHandle != NULL) {
-        CHECK(mDrmManagerClient);
-        if (RightsStatus::RIGHTS_VALID != mDecryptHandle->status) {
-            notifyListener_l(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, ERROR_DRM_NO_LICENSE);
+        if (mDecryptHandle != NULL) {
+            CHECK(mDrmManagerClient);
+            if (RightsStatus::RIGHTS_VALID != mDecryptHandle->status) {
+                notifyListener_l(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, ERROR_DRM_NO_LICENSE);
+            }
         }
     }
 
diff --git a/media/libstagefright/MediaExtractor.cpp b/media/libstagefright/MediaExtractor.cpp
index 2171492..d65dc51 100644
--- a/media/libstagefright/MediaExtractor.cpp
+++ b/media/libstagefright/MediaExtractor.cpp
@@ -114,6 +114,9 @@
         ret = new AVIExtractor(source);
     } else if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_WVM)) {
         ret = new WVMExtractor(source);
+        if (ret != NULL) {
+            isDrm = true;
+        }
     } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC_ADTS)) {
         ret = new AACExtractor(source, meta);
     } else if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_MPEG2PS)) {
diff --git a/media/libstagefright/rtsp/AAMRAssembler.cpp b/media/libstagefright/rtsp/AAMRAssembler.cpp
index 547b202..9d72b1f 100644
--- a/media/libstagefright/rtsp/AAMRAssembler.cpp
+++ b/media/libstagefright/rtsp/AAMRAssembler.cpp
@@ -79,13 +79,17 @@
 }
 
 static size_t getFrameSize(bool isWide, unsigned FT) {
-    static const size_t kFrameSizeNB[8] = {
-        95, 103, 118, 134, 148, 159, 204, 244
+    static const size_t kFrameSizeNB[9] = {
+        95, 103, 118, 134, 148, 159, 204, 244, 39
     };
-    static const size_t kFrameSizeWB[9] = {
-        132, 177, 253, 285, 317, 365, 397, 461, 477
+    static const size_t kFrameSizeWB[10] = {
+        132, 177, 253, 285, 317, 365, 397, 461, 477, 40
     };
 
+    if (FT == 15) {
+        return 1;
+    }
+
     size_t frameSize = isWide ? kFrameSizeWB[FT] : kFrameSizeNB[FT];
 
     // Round up bits to bytes and add 1 for the header byte.
@@ -161,8 +165,8 @@
 
         unsigned FT = (toc >> 3) & 0x0f;
         if ((toc & 3) != 0
-                || (mIsWide && FT > 8)
-                || (!mIsWide && FT > 7)) {
+                || (mIsWide && FT > 9 && FT != 15)
+                || (!mIsWide && FT > 8 && FT != 15)) {
             queue->erase(queue->begin());
             ++mNextExpectedSeqNo;
 
diff --git a/media/libstagefright/rtsp/ARTSPConnection.cpp b/media/libstagefright/rtsp/ARTSPConnection.cpp
index 0fbbb9e..d8107bc 100644
--- a/media/libstagefright/rtsp/ARTSPConnection.cpp
+++ b/media/libstagefright/rtsp/ARTSPConnection.cpp
@@ -659,6 +659,7 @@
     }
 
     AString line;
+    ssize_t lastDictIndex = -1;
     for (;;) {
         if (!receiveLine(&line)) {
             break;
@@ -668,7 +669,21 @@
             break;
         }
 
-        ALOGV("line: %s", line.c_str());
+        ALOGV("line: '%s'", line.c_str());
+
+        if (line.c_str()[0] == ' ' || line.c_str()[0] == '\t') {
+            // Support for folded header values.
+
+            if (lastDictIndex < 0) {
+                // First line cannot be a continuation of the previous one.
+                return false;
+            }
+
+            AString &value = response->mHeaders.editValueAt(lastDictIndex);
+            value.append(line);
+
+            continue;
+        }
 
         ssize_t colonPos = line.find(":");
         if (colonPos < 0) {
@@ -681,9 +696,12 @@
         key.tolower();
 
         line.erase(0, colonPos + 1);
-        line.trim();
 
-        response->mHeaders.add(key, line);
+        lastDictIndex = response->mHeaders.add(key, line);
+    }
+
+    for (size_t i = 0; i < response->mHeaders.size(); ++i) {
+        response->mHeaders.editValueAt(i).trim();
     }
 
     unsigned long contentLength = 0;
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_rotate_on.png b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_rotate_on.png
index 6208581..02da243 100644
--- a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_rotate_on.png
+++ b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_rotate_on.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_wifi_on.png b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_wifi_on.png
index fe4d318..d645a3c 100644
--- a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_wifi_on.png
+++ b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_wifi_on.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_rotate_on.png b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_rotate_on.png
index 2536d92..9c117ae 100644
--- a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_rotate_on.png
+++ b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_rotate_on.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_wifi_on.png b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_wifi_on.png
index 44e3577..4f51201 100644
--- a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_wifi_on.png
+++ b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_wifi_on.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_rotate_on.png b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_rotate_on.png
index b375396..35d85e1 100644
--- a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_rotate_on.png
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_rotate_on.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_wifi_on.png b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_wifi_on.png
index 54e3d1e..bc1628f 100644
--- a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_wifi_on.png
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_wifi_on.png
Binary files differ
diff --git a/services/java/com/android/server/WifiService.java b/services/java/com/android/server/WifiService.java
index 75f1408..016dc82 100644
--- a/services/java/com/android/server/WifiService.java
+++ b/services/java/com/android/server/WifiService.java
@@ -152,8 +152,12 @@
     /* Wifi disabled due to airplane mode on */
     private static final int WIFI_DISABLED_AIRPLANE_ON      = 3;
 
-    private AtomicInteger mWifiState = new AtomicInteger(WIFI_DISABLED);
+    /* Persisted state that tracks the wifi & airplane interaction from settings */
+    private AtomicInteger mPersistWifiState = new AtomicInteger(WIFI_DISABLED);
+    /* Tracks current airplane mode state */
     private AtomicBoolean mAirplaneModeOn = new AtomicBoolean(false);
+    /* Tracks whether wifi is enabled from WifiStateMachine's perspective */
+    private boolean mWifiEnabled;
 
     private boolean mIsReceiverRegistered = false;
 
@@ -373,8 +377,8 @@
                         mAirplaneModeOn.set(isAirplaneModeOn());
                         /* On airplane mode disable, restore wifi state if necessary */
                         if (!mAirplaneModeOn.get() && (testAndClearWifiSavedState() ||
-                            mWifiState.get() == WIFI_ENABLED_AIRPLANE_OVERRIDE)) {
-                                persistWifiEnabled(true);
+                            mPersistWifiState.get() == WIFI_ENABLED_AIRPLANE_OVERRIDE)) {
+                                persistWifiState(true);
                         }
                         updateWifiState();
                     }
@@ -391,7 +395,12 @@
                     @Override
                     public void onReceive(Context context, Intent intent) {
                         if (intent.getAction().equals(WifiManager.WIFI_STATE_CHANGED_ACTION)) {
-                            // reset & clear notification on any wifi state change
+                            int wifiState = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE,
+                                    WifiManager.WIFI_STATE_DISABLED);
+
+                            mWifiEnabled = (wifiState == WifiManager.WIFI_STATE_ENABLED);
+
+                           // reset & clear notification on any wifi state change
                             resetNotification();
                         } else if (intent.getAction().equals(
                                 WifiManager.NETWORK_STATE_CHANGED_ACTION)) {
@@ -435,7 +444,7 @@
      */
     public void checkAndStartWifi() {
         mAirplaneModeOn.set(isAirplaneModeOn());
-        mWifiState.set(getPersistedWifiState());
+        mPersistWifiState.set(getPersistedWifiState());
         /* Start if Wi-Fi should be enabled or the saved state indicates Wi-Fi was on */
         boolean wifiEnabled = shouldWifiBeEnabled() || testAndClearWifiSavedState();
         Slog.i(TAG, "WifiService starting up with Wi-Fi " +
@@ -472,29 +481,30 @@
 
     private boolean shouldWifiBeEnabled() {
         if (mAirplaneModeOn.get()) {
-            return mWifiState.get() == WIFI_ENABLED_AIRPLANE_OVERRIDE;
+            return mPersistWifiState.get() == WIFI_ENABLED_AIRPLANE_OVERRIDE;
         } else {
-            return mWifiState.get() != WIFI_DISABLED;
+            return mPersistWifiState.get() != WIFI_DISABLED;
         }
     }
 
-    private void persistWifiEnabled(boolean enabled) {
+    private void persistWifiState(boolean enabled) {
         final ContentResolver cr = mContext.getContentResolver();
         boolean airplane = mAirplaneModeOn.get() && isAirplaneToggleable();
         if (enabled) {
             if (airplane) {
-                mWifiState.set(WIFI_ENABLED_AIRPLANE_OVERRIDE);
+                mPersistWifiState.set(WIFI_ENABLED_AIRPLANE_OVERRIDE);
             } else {
-                mWifiState.set(WIFI_ENABLED);
+                mPersistWifiState.set(WIFI_ENABLED);
             }
         } else {
             if (airplane) {
-                mWifiState.set(WIFI_DISABLED_AIRPLANE_ON);
+                mPersistWifiState.set(WIFI_DISABLED_AIRPLANE_ON);
             } else {
-                mWifiState.set(WIFI_DISABLED);
+                mPersistWifiState.set(WIFI_DISABLED);
             }
         }
-        Settings.Secure.putInt(cr, Settings.Secure.WIFI_ON, mWifiState.get());
+
+        Settings.Secure.putInt(cr, Settings.Secure.WIFI_ON, mPersistWifiState.get());
     }
 
 
@@ -545,7 +555,6 @@
      */
     public synchronized boolean setWifiEnabled(boolean enable) {
         enforceChangePermission();
-
         if (DBG) {
             Slog.e(TAG, "Invoking mWifiStateMachine.setWifiEnabled\n");
         }
@@ -559,16 +568,20 @@
          * Caller might not have WRITE_SECURE_SETTINGS,
          * only CHANGE_WIFI_STATE is enforced
          */
-        long ident = Binder.clearCallingIdentity();
-        persistWifiEnabled(enable);
-        Binder.restoreCallingIdentity(ident);
+
+        /* Avoids overriding of airplane state when wifi is already in the expected state */
+        if (enable != mWifiEnabled) {
+            long ident = Binder.clearCallingIdentity();
+            persistWifiState(enable);
+            Binder.restoreCallingIdentity(ident);
+        }
 
         if (enable) {
             if (!mIsReceiverRegistered) {
                 registerForBroadcasts();
                 mIsReceiverRegistered = true;
             }
-        } else if (mIsReceiverRegistered){
+        } else if (mIsReceiverRegistered) {
             mContext.unregisterReceiver(mReceiver);
             mIsReceiverRegistered = false;
         }
diff --git a/services/java/com/android/server/connectivity/Tethering.java b/services/java/com/android/server/connectivity/Tethering.java
index b1551a6..bc8ce7d 100644
--- a/services/java/com/android/server/connectivity/Tethering.java
+++ b/services/java/com/android/server/connectivity/Tethering.java
@@ -118,7 +118,7 @@
         "192.168.48.2", "192.168.48.254",
     };
 
-    private String[] mDnsServers;
+    private String[] mDefaultDnsServers;
     private static final String DNS_DEFAULT_SERVER1 = "8.8.8.8";
     private static final String DNS_DEFAULT_SERVER2 = "8.8.4.4";
 
@@ -171,9 +171,9 @@
         updateConfiguration();
 
         // TODO - remove and rely on real notifications of the current iface
-        mDnsServers = new String[2];
-        mDnsServers[0] = DNS_DEFAULT_SERVER1;
-        mDnsServers[1] = DNS_DEFAULT_SERVER2;
+        mDefaultDnsServers = new String[2];
+        mDefaultDnsServers[0] = DNS_DEFAULT_SERVER1;
+        mDefaultDnsServers[1] = DNS_DEFAULT_SERVER2;
     }
 
     void updateConfiguration() {
@@ -1244,7 +1244,7 @@
                     }
                 }
                 try {
-                    mNMService.setDnsForwarders(mDnsServers);
+                    mNMService.setDnsForwarders(mDefaultDnsServers);
                 } catch (Exception e) {
                     transitionTo(mSetDnsForwardersErrorState);
                     return false;
@@ -1320,7 +1320,19 @@
                     try {
                         linkProperties = mConnService.getLinkProperties(upType);
                     } catch (RemoteException e) { }
-                    if (linkProperties != null) iface = linkProperties.getInterfaceName();
+                    if (linkProperties != null) {
+                        iface = linkProperties.getInterfaceName();
+                        String[] dnsServers = mDefaultDnsServers;
+                        Collection<InetAddress> dnses = linkProperties.getDnses();
+                        if (dnses != null) {
+                            dnsServers = NetworkUtils.makeStrings(dnses);
+                        }
+                        try {
+                            mNMService.setDnsForwarders(dnsServers);
+                        } catch (Exception e) {
+                            transitionTo(mSetDnsForwardersErrorState);
+                        }
+                    }
                 }
                 notifyTetheredOfNewUpstreamIface(iface);
             }
diff --git a/services/java/com/android/server/connectivity/Vpn.java b/services/java/com/android/server/connectivity/Vpn.java
index 55e0678..72cf512 100644
--- a/services/java/com/android/server/connectivity/Vpn.java
+++ b/services/java/com/android/server/connectivity/Vpn.java
@@ -482,6 +482,7 @@
                 if (state.exists()) {
                     throw new IllegalStateException("Cannot delete the state");
                 }
+                new File("/data/misc/vpn/abort").delete();
 
                 // Check if we need to restart any of the daemons.
                 boolean restart = false;