Merge "Use the carrier-given dns addrs for tethering."
diff --git a/core/java/android/text/SpannableStringBuilder.java b/core/java/android/text/SpannableStringBuilder.java
index 231f913..b708750 100644
--- a/core/java/android/text/SpannableStringBuilder.java
+++ b/core/java/android/text/SpannableStringBuilder.java
@@ -863,6 +863,17 @@
         return new String(buf);
     }
 
+    /**
+     * Return a String containing a copy of the chars in this buffer, limited to the
+     * [start, end[ range.
+     * @hide
+     */
+    public String substring(int start, int end) {
+        char[] buf = new char[end - start];
+        getChars(start, end, buf, 0);
+        return new String(buf);
+    }
+
     private TextWatcher[] sendTextWillChange(int start, int before, int after) {
         TextWatcher[] recip = getSpans(start, start + before, TextWatcher.class);
         int n = recip.length;
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/text/method/WordIterator.java b/core/java/android/text/method/WordIterator.java
index 239d9e8..11226a9 100644
--- a/core/java/android/text/method/WordIterator.java
+++ b/core/java/android/text/method/WordIterator.java
@@ -18,6 +18,7 @@
 package android.text.method;
 
 import android.text.Selection;
+import android.text.SpannableStringBuilder;
 
 import java.text.BreakIterator;
 import java.util.Locale;
@@ -58,7 +59,11 @@
         mOffsetShift = Math.max(0, start - WINDOW_WIDTH);
         final int windowEnd = Math.min(charSequence.length(), end + WINDOW_WIDTH);
 
-        mString = charSequence.toString().substring(mOffsetShift, windowEnd);
+        if (charSequence instanceof SpannableStringBuilder) {
+            mString = ((SpannableStringBuilder) charSequence).substring(mOffsetShift, windowEnd);
+        } else {
+            mString = charSequence.subSequence(mOffsetShift, windowEnd).toString();
+        }
         mIterator.setText(mString);
     }
 
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/NumberPicker.java b/core/java/android/widget/NumberPicker.java
index 9d541e0..7d0f98e 100644
--- a/core/java/android/widget/NumberPicker.java
+++ b/core/java/android/widget/NumberPicker.java
@@ -774,6 +774,7 @@
                 mBeginEditOnUpEvent = false;
                 mAdjustScrollerOnUpEvent = true;
                 if (mSelectorWheelState == SELECTOR_WHEEL_STATE_LARGE) {
+                    mSelectorWheelPaint.setAlpha(SELECTOR_WHEEL_BRIGHT_ALPHA);
                     boolean scrollersFinished = mFlingScroller.isFinished()
                             && mAdjustScroller.isFinished();
                     if (!scrollersFinished) {
@@ -1608,23 +1609,11 @@
      */
     private void fling(int velocityY) {
         mPreviousScrollerY = 0;
-        Scroller flingScroller = mFlingScroller;
 
-        if (mWrapSelectorWheel) {
-            if (velocityY > 0) {
-                flingScroller.fling(0, 0, 0, velocityY, 0, 0, 0, Integer.MAX_VALUE);
-            } else {
-                flingScroller.fling(0, Integer.MAX_VALUE, 0, velocityY, 0, 0, 0, Integer.MAX_VALUE);
-            }
+        if (velocityY > 0) {
+            mFlingScroller.fling(0, 0, 0, velocityY, 0, 0, 0, Integer.MAX_VALUE);
         } else {
-            if (velocityY > 0) {
-                int maxY = mTextSize * (mValue - mMinValue);
-                flingScroller.fling(0, 0, 0, velocityY, 0, 0, 0, maxY);
-            } else {
-                int startY = mTextSize * (mMaxValue - mValue);
-                int maxY = startY;
-                flingScroller.fling(0, startY, 0, velocityY, 0, 0, 0, maxY);
-            }
+            mFlingScroller.fling(0, Integer.MAX_VALUE, 0, velocityY, 0, 0, 0, Integer.MAX_VALUE);
         }
 
         invalidate();
diff --git a/core/java/android/widget/SpellChecker.java b/core/java/android/widget/SpellChecker.java
index 4bd7165..31da5b5 100644
--- a/core/java/android/widget/SpellChecker.java
+++ b/core/java/android/widget/SpellChecker.java
@@ -19,6 +19,7 @@
 import android.content.Context;
 import android.text.Editable;
 import android.text.Selection;
+import android.text.SpannableStringBuilder;
 import android.text.Spanned;
 import android.text.method.WordIterator;
 import android.text.style.SpellCheckSpan;
@@ -220,7 +221,6 @@
         TextInfo[] textInfos = new TextInfo[mLength];
         int textInfosCount = 0;
 
-        final String text = editable.toString();
         for (int i = 0; i < mLength; i++) {
             final SpellCheckSpan spellCheckSpan = mSpellCheckSpans[i];
             if (spellCheckSpan.isSpellCheckInProgress()) continue;
@@ -230,7 +230,9 @@
 
             // Do not check this word if the user is currently editing it
             if (start >= 0 && end > start && (selectionEnd < start || selectionStart > end)) {
-                final String word = text.substring(start, end);
+                final String word = (editable instanceof SpannableStringBuilder) ?
+                        ((SpannableStringBuilder) editable).substring(start, end) :
+                        editable.subSequence(start, end).toString();
                 spellCheckSpan.setSpellCheckInProgress(true);
                 textInfos[textInfosCount++] = new TextInfo(word, mCookie, mIds[i]);
             }
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index db9629a..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
@@ -5517,7 +5510,7 @@
                      * call performClick(), but that won't do anything in
                      * this case.)
                      */
-                    if (hasOnClickListeners()) {
+                    if (!hasOnClickListeners()) {
                         if (mMovement != null && mText instanceof Editable
                                 && mLayout != null && onCheckIsTextEditor()) {
                             InputMethodManager imm = InputMethodManager.peekInstance();
@@ -5554,7 +5547,7 @@
                          * call performClick(), but that won't do anything in
                          * this case.)
                          */
-                        if (hasOnClickListeners()) {
+                        if (!hasOnClickListeners()) {
                             View v = focusSearch(FOCUS_DOWN);
 
                             if (v != null) {
@@ -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/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index f702657..80aef215 100755
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -1992,7 +1992,7 @@
     <string name="save_password_label">Confirm</string>
 
     <!-- Toast for double-tap -->
-    <string name="double_tap_toast">Tip: Double-touch to zoom in and out.</string>
+    <string name="double_tap_toast">Tip: Double-tap to zoom in and out.</string>
 
     <!-- Text to show in the auto complete drop down list on a text view when the WebView can auto fill the entire form, and the user has configured an AutoFill profile [CHAR-LIMIT=8] -->
     <string name="autofill_this_form">Autofill</string>
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 e72adc4..6d28298 100644
--- a/media/libmediaplayerservice/nuplayer/RTSPSource.cpp
+++ b/media/libmediaplayerservice/nuplayer/RTSPSource.cpp
@@ -38,7 +38,8 @@
       mFlags(0),
       mState(DISCONNECTED),
       mFinalResult(OK),
-      mDisconnectReplyID(0) {
+      mDisconnectReplyID(0),
+      mSeekGeneration(0) {
     if (headers) {
         mExtraHeaders = *headers;
 
@@ -146,14 +147,21 @@
 }
 
 status_t NuPlayer::RTSPSource::seekTo(int64_t seekTimeUs) {
+    sp<AMessage> msg = new AMessage(kWhatPerformSeek, mReflector->id());
+    msg->setInt32("generation", ++mSeekGeneration);
+    msg->setInt64("timeUs", seekTimeUs);
+    msg->post(200000ll);
+
+    return OK;
+}
+
+void NuPlayer::RTSPSource::performSeek(int64_t seekTimeUs) {
     if (mState != CONNECTED) {
-        return UNKNOWN_ERROR;
+        return;
     }
 
     mState = SEEKING;
     mHandler->seek(seekTimeUs);
-
-    return OK;
 }
 
 bool NuPlayer::RTSPSource::isSeekable() {
@@ -168,6 +176,20 @@
         mDisconnectReplyID = replyID;
         finishDisconnectIfPossible();
         return;
+    } else if (msg->what() == kWhatPerformSeek) {
+        int32_t generation;
+        CHECK(msg->findInt32("generation", &generation));
+
+        if (generation != mSeekGeneration) {
+            // obsolete.
+            return;
+        }
+
+        int64_t seekTimeUs;
+        CHECK(msg->findInt64("timeUs", &seekTimeUs));
+
+        performSeek(seekTimeUs);
+        return;
     }
 
     CHECK_EQ(msg->what(), (int)kWhatNotify);
@@ -208,21 +230,32 @@
                 break;
             }
 
-            const TrackInfo &info = mTracks.editItemAt(trackIndex);
-            sp<AnotherPacketSource> source = info.mSource;
+            TrackInfo *info = &mTracks.editItemAt(trackIndex);
+
+            sp<AnotherPacketSource> source = info->mSource;
             if (source != NULL) {
-#if 1
                 uint32_t rtpTime;
                 CHECK(accessUnit->meta()->findInt32("rtp-time", (int32_t *)&rtpTime));
 
+                if (!info->mNPTMappingValid) {
+                    // This is a live stream, we didn't receive any normal
+                    // playtime mapping. Assume the first packets correspond
+                    // to time 0.
+
+                    ALOGV("This is a live stream, assuming time = 0");
+
+                    info->mRTPTime = rtpTime;
+                    info->mNormalPlaytimeUs = 0ll;
+                    info->mNPTMappingValid = true;
+                }
+
                 int64_t nptUs =
-                    ((double)rtpTime - (double)info.mRTPTime)
-                        / info.mTimeScale
+                    ((double)rtpTime - (double)info->mRTPTime)
+                        / info->mTimeScale
                         * 1000000ll
-                        + info.mNormalPlaytimeUs;
+                        + info->mNormalPlaytimeUs;
 
                 accessUnit->meta()->setInt64("timeUs", nptUs);
-#endif
 
                 source->queueAccessUnit(accessUnit);
             }
@@ -278,6 +311,7 @@
             TrackInfo *info = &mTracks.editItemAt(trackIndex);
             info->mRTPTime = rtpTime;
             info->mNormalPlaytimeUs = nptUs;
+            info->mNPTMappingValid = true;
             break;
         }
 
@@ -305,6 +339,7 @@
         info.mTimeScale = timeScale;
         info.mRTPTime = 0;
         info.mNormalPlaytimeUs = 0ll;
+        info.mNPTMappingValid = false;
 
         if ((isAudio && mAudioTrack == NULL)
                 || (isVideo && mVideoTrack == NULL)) {
diff --git a/media/libmediaplayerservice/nuplayer/RTSPSource.h b/media/libmediaplayerservice/nuplayer/RTSPSource.h
index 66eab72..59d06ad 100644
--- a/media/libmediaplayerservice/nuplayer/RTSPSource.h
+++ b/media/libmediaplayerservice/nuplayer/RTSPSource.h
@@ -56,6 +56,7 @@
     enum {
         kWhatNotify          = 'noti',
         kWhatDisconnect      = 'disc',
+        kWhatPerformSeek     = 'seek',
     };
 
     enum State {
@@ -76,6 +77,7 @@
         int32_t mTimeScale;
         uint32_t mRTPTime;
         int64_t mNormalPlaytimeUs;
+        bool mNPTMappingValid;
     };
 
     AString mURL;
@@ -95,12 +97,16 @@
     sp<AnotherPacketSource> mAudioTrack;
     sp<AnotherPacketSource> mVideoTrack;
 
+    int32_t mSeekGeneration;
+
     sp<AnotherPacketSource> getSource(bool audio);
 
     void onConnected();
     void onDisconnected(const sp<AMessage> &msg);
     void finishDisconnectIfPossible();
 
+    void performSeek(int64_t seekTimeUs);
+
     DISALLOW_EVIL_CONSTRUCTORS(RTSPSource);
 };
 
diff --git a/media/libstagefright/foundation/ABitReader.cpp b/media/libstagefright/foundation/ABitReader.cpp
index f07dd4f..5499c32 100644
--- a/media/libstagefright/foundation/ABitReader.cpp
+++ b/media/libstagefright/foundation/ABitReader.cpp
@@ -79,7 +79,13 @@
 }
 
 void ABitReader::putBits(uint32_t x, size_t n) {
-    CHECK_LE(mNumBitsLeft + n, 32u);
+    CHECK_LE(n, 32u);
+
+    while (mNumBitsLeft + n > 32) {
+        mNumBitsLeft -= 8;
+        --mData;
+        ++mSize;
+    }
 
     mReservoir = (mReservoir >> n) | (x << (32 - n));
     mNumBitsLeft += n;
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/media/libstagefright/rtsp/MyHandler.h b/media/libstagefright/rtsp/MyHandler.h
index dd049c2..21ef298 100644
--- a/media/libstagefright/rtsp/MyHandler.h
+++ b/media/libstagefright/rtsp/MyHandler.h
@@ -1100,6 +1100,8 @@
         float npt1, npt2;
         if (!ASessionDescription::parseNTPRange(val.c_str(), &npt1, &npt2)) {
             // This is a live stream and therefore not seekable.
+
+            LOGI("This is a live stream");
             return;
         }
 
@@ -1386,12 +1388,14 @@
             msg->setInt32("what", kWhatConnected);
             msg->post();
 
-            for (size_t i = 0; i < mTracks.size(); ++i) {
-                TrackInfo *info = &mTracks.editItemAt(i);
+            if (mSeekable) {
+                for (size_t i = 0; i < mTracks.size(); ++i) {
+                    TrackInfo *info = &mTracks.editItemAt(i);
 
-                postNormalPlayTimeMapping(
-                        i,
-                        info->mNormalPlayTimeRTP, info->mNormalPlayTimeUs);
+                    postNormalPlayTimeMapping(
+                            i,
+                            info->mNormalPlayTimeRTP, info->mNormalPlayTimeUs);
+                }
             }
 
             mFirstAccessUnit = false;
diff --git a/policy/src/com/android/internal/policy/impl/LockPatternKeyguardView.java b/policy/src/com/android/internal/policy/impl/LockPatternKeyguardView.java
index 67a6855..088146b 100644
--- a/policy/src/com/android/internal/policy/impl/LockPatternKeyguardView.java
+++ b/policy/src/com/android/internal/policy/impl/LockPatternKeyguardView.java
@@ -52,6 +52,7 @@
 import android.os.Message;
 import android.os.IBinder;
 import android.os.Parcelable;
+import android.os.PowerManager;
 import android.os.RemoteException;
 import android.os.SystemClock;
 import android.os.SystemProperties;
@@ -101,8 +102,8 @@
     private View mLockScreen;
     private View mUnlockScreen;
 
-    private volatile boolean mScreenOn = false;
-    private volatile boolean mWindowFocused = false;
+    private boolean mScreenOn;
+    private boolean mWindowFocused = false;
     private boolean mEnableFallback = false; // assume no fallback UI until we know better
 
     private boolean mShowLockBeforeUnlock = false;
@@ -311,6 +312,7 @@
         mWindowController = controller;
         mHasOverlay = false;
         mPluggedIn = mUpdateMonitor.isDevicePluggedIn();
+        mScreenOn = ((PowerManager)context.getSystemService(Context.POWER_SERVICE)).isScreenOn();
 
         mUpdateMonitor.registerInfoCallback(this);
 
diff --git a/services/java/com/android/server/WifiService.java b/services/java/com/android/server/WifiService.java
index 16643ff..aef3426 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;
         }
@@ -840,7 +853,7 @@
          * of WifiLock & device idle status unless wifi enabled status is toggled
          */
 
-        mWifiStateMachine.setDriverStart(true);
+        mWifiStateMachine.setDriverStart(true, mEmergencyCallbackMode);
         mWifiStateMachine.reconnectCommand();
     }
 
@@ -854,7 +867,7 @@
          * TODO: if a stop is issued, wifi is brought up only by startWifi
          * unless wifi enabled status is toggled
          */
-        mWifiStateMachine.setDriverStart(false);
+        mWifiStateMachine.setDriverStart(false, mEmergencyCallbackMode);
     }
 
 
@@ -1074,11 +1087,11 @@
                 mWifiStateMachine.setWifiEnabled(true);
                 mWifiStateMachine.setScanOnlyMode(
                         strongestLockMode == WifiManager.WIFI_MODE_SCAN_ONLY);
-                mWifiStateMachine.setDriverStart(true);
+                mWifiStateMachine.setDriverStart(true, mEmergencyCallbackMode);
                 mWifiStateMachine.setHighPerfModeEnabled(strongestLockMode
                         == WifiManager.WIFI_MODE_FULL_HIGH_PERF);
             } else {
-                mWifiStateMachine.setDriverStart(false);
+                mWifiStateMachine.setDriverStart(false, mEmergencyCallbackMode);
             }
         } else {
             mWifiStateMachine.setWifiEnabled(false);
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;
diff --git a/services/java/com/android/server/location/ComprehensiveCountryDetector.java b/services/java/com/android/server/location/ComprehensiveCountryDetector.java
index bb9e60f..f068b44 100755
--- a/services/java/com/android/server/location/ComprehensiveCountryDetector.java
+++ b/services/java/com/android/server/location/ComprehensiveCountryDetector.java
@@ -66,26 +66,12 @@
     protected CountryDetectorBase mLocationBasedCountryDetector;
     protected Timer mLocationRefreshTimer;
 
-    private final int mPhoneType;
     private Country mCountry;
-    private TelephonyManager mTelephonyManager;
+    private final TelephonyManager mTelephonyManager;
     private Country mCountryFromLocation;
     private boolean mStopped = false;
-    private ServiceState mLastState;
 
-    private PhoneStateListener mPhoneStateListener = new PhoneStateListener() {
-        @Override
-        public void onServiceStateChanged(ServiceState serviceState) {
-            // TODO: Find out how often we will be notified, if this method is called too
-            // many times, let's consider querying the network.
-            Slog.d(TAG, "onServiceStateChanged");
-            // We only care the state change
-            if (mLastState == null || mLastState.getState() != serviceState.getState()) {
-                detectCountry(true, true);
-                mLastState = new ServiceState(serviceState);
-            }
-        }
-    };
+    private PhoneStateListener mPhoneStateListener;
 
     /**
      * The listener for receiving the notification from LocationBasedCountryDetector.
@@ -104,7 +90,6 @@
     public ComprehensiveCountryDetector(Context context) {
         super(context);
         mTelephonyManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
-        mPhoneType = mTelephonyManager.getPhoneType();
     }
 
     @Override
@@ -115,6 +100,7 @@
 
     @Override
     public void stop() {
+        // Note: this method in this subclass called only by tests.
         Slog.i(TAG, "Stop the detector.");
         cancelLocationRefresh();
         removePhoneStateListener();
@@ -141,14 +127,20 @@
         return result;
     }
 
+    private boolean isNetworkCountryCodeAvailable() {
+        // On CDMA TelephonyManager.getNetworkCountryIso() just returns SIM country.  We don't want
+        // to prioritize it over location based country, so ignore it.
+        final int phoneType = mTelephonyManager.getPhoneType();
+        if (DEBUG) Slog.v(TAG, "    phonetype=" + phoneType);
+        return phoneType == TelephonyManager.PHONE_TYPE_GSM;
+    }
+
     /**
      * @return the country from the mobile network.
      */
     protected Country getNetworkBasedCountry() {
         String countryIso = null;
-        // TODO: The document says the result may be unreliable on CDMA networks. Shall we use
-        // it on CDMA phone? We may test the Android primarily used countries.
-        if (mPhoneType == TelephonyManager.PHONE_TYPE_GSM) {
+        if (isNetworkCountryCodeAvailable()) {
             countryIso = mTelephonyManager.getNetworkCountryIso();
             if (!TextUtils.isEmpty(countryIso)) {
                 return new Country(countryIso, Country.COUNTRY_SOURCE_NETWORK);
@@ -356,20 +348,16 @@
     }
 
     protected synchronized void addPhoneStateListener() {
-        if (mPhoneStateListener == null && mPhoneType == TelephonyManager.PHONE_TYPE_GSM) {
-            mLastState = null;
+        if (mPhoneStateListener == null) {
             mPhoneStateListener = new PhoneStateListener() {
                 @Override
                 public void onServiceStateChanged(ServiceState serviceState) {
-                    // TODO: Find out how often we will be notified, if this
-                    // method is called too
-                    // many times, let's consider querying the network.
-                    Slog.d(TAG, "onServiceStateChanged");
-                    // We only care the state change
-                    if (mLastState == null || mLastState.getState() != serviceState.getState()) {
-                        detectCountry(true, true);
-                        mLastState = new ServiceState(serviceState);
+                    if (!isNetworkCountryCodeAvailable()) {
+                        return;
                     }
+                    if (DEBUG) Slog.d(TAG, "onServiceStateChanged: " + serviceState.getState());
+
+                    detectCountry(true, true);
                 }
             };
             mTelephonyManager.listen(mPhoneStateListener, PhoneStateListener.LISTEN_SERVICE_STATE);
diff --git a/services/tests/servicestests/src/com/android/server/location/LocationBasedCountryDetectorTest.java b/services/tests/servicestests/src/com/android/server/location/LocationBasedCountryDetectorTest.java
index 60677df..5f5d668 100755
--- a/services/tests/servicestests/src/com/android/server/location/LocationBasedCountryDetectorTest.java
+++ b/services/tests/servicestests/src/com/android/server/location/LocationBasedCountryDetectorTest.java
@@ -213,7 +213,7 @@
         // QueryThread should be set to NULL
         assertNull(detector.getQueryThread());
         assertTrue(countryListener.notified());
-        assertEquals(countryListener.getCountry(), country);
+        assertEquals("us", countryListener.getCountry().toLowerCase());
     }
 
     public void testFindingCountryCancelled() {
@@ -238,7 +238,7 @@
         // QueryThread should be set to NULL
         assertNull(detector.getQueryThread());
         assertTrue(countryListener.notified());
-        assertEquals(countryListener.getCountry(), country);
+        assertEquals("us", countryListener.getCountry().toLowerCase());
     }
 
     public void testFindingLocationCancelled() {
@@ -339,7 +339,7 @@
         assertNull(detector.getQueryThread());
         // CountryListener should be notified
         assertTrue(countryListener.notified());
-        assertEquals(countryListener.getCountry(), country);
+        assertEquals("us", countryListener.getCountry().toLowerCase());
     }
 
     private void waitForTimerReset(TestCountryDetector detector) {
diff --git a/wifi/java/android/net/wifi/WifiStateMachine.java b/wifi/java/android/net/wifi/WifiStateMachine.java
index b609ba9..5437caa 100644
--- a/wifi/java/android/net/wifi/WifiStateMachine.java
+++ b/wifi/java/android/net/wifi/WifiStateMachine.java
@@ -368,6 +368,10 @@
     private static final int SUCCESS = 1;
     private static final int FAILURE = -1;
 
+    /* Phone in emergency call back mode */
+    private static final int IN_ECM_STATE = 1;
+    private static final int NOT_IN_ECM_STATE = 0;
+
     /**
      * The maximum number of times we will retry a connection to an access point
      * for which we have failed in acquiring an IP address from DHCP. A value of
@@ -773,11 +777,11 @@
     /**
      * TODO: doc
      */
-    public void setDriverStart(boolean enable) {
+    public void setDriverStart(boolean enable, boolean ecm) {
         if (enable) {
             sendMessage(CMD_START_DRIVER);
         } else {
-            sendMessage(CMD_STOP_DRIVER);
+            sendMessage(obtainMessage(CMD_STOP_DRIVER, ecm ? IN_ECM_STATE : NOT_IN_ECM_STATE, 0));
         }
     }
 
@@ -2567,16 +2571,25 @@
                     WifiNative.setBluetoothCoexistenceScanModeCommand(mBluetoothConnectionActive);
                     break;
                 case CMD_STOP_DRIVER:
-                    /* Already doing a delayed stop */
-                    if (mInDelayedStop) {
+                    int mode = message.arg1;
+
+                    /* Already doing a delayed stop && not in ecm state */
+                    if (mInDelayedStop && mode != IN_ECM_STATE) {
                         if (DBG) log("Already in delayed stop");
                         break;
                     }
                     mInDelayedStop = true;
                     mDelayedStopCounter++;
                     if (DBG) log("Delayed stop message " + mDelayedStopCounter);
-                    sendMessageDelayed(obtainMessage(CMD_DELAYED_STOP_DRIVER, mDelayedStopCounter,
-                            0), DELAYED_DRIVER_STOP_MS);
+
+                    if (mode == IN_ECM_STATE) {
+                        /* send a shut down immediately */
+                        sendMessage(obtainMessage(CMD_DELAYED_STOP_DRIVER, mDelayedStopCounter, 0));
+                    } else {
+                        /* send regular delayed shut down */
+                        sendMessageDelayed(obtainMessage(CMD_DELAYED_STOP_DRIVER,
+                                mDelayedStopCounter, 0), DELAYED_DRIVER_STOP_MS);
+                    }
                     break;
                 case CMD_START_DRIVER:
                     if (mInDelayedStop) {