Merge "Release the constraint on the requested version." into jb-dev
diff --git a/core/java/android/nfc/NfcActivityManager.java b/core/java/android/nfc/NfcActivityManager.java
index 7ffa575..53b41d5 100644
--- a/core/java/android/nfc/NfcActivityManager.java
+++ b/core/java/android/nfc/NfcActivityManager.java
@@ -299,7 +299,23 @@
             callback = state.uriCallback;
         }
         if (callback != null) {
-            return callback.createBeamUris(mDefaultEvent);
+            uris = callback.createBeamUris(mDefaultEvent);
+            if (uris != null) {
+                for (Uri uri : uris) {
+                    if (uri == null) {
+                        Log.e(TAG, "Uri not allowed to be null.");
+                        return null;
+                    }
+                    String scheme = uri.getScheme();
+                    if (scheme == null || (!scheme.equalsIgnoreCase("file") &&
+                            !scheme.equalsIgnoreCase("content"))) {
+                        Log.e(TAG, "Uri needs to have " +
+                                "either scheme file or scheme content");
+                        return null;
+                    }
+                }
+            }
+            return uris;
         } else {
             return uris;
         }
diff --git a/core/java/android/nfc/NfcAdapter.java b/core/java/android/nfc/NfcAdapter.java
index 7bf9feb..4464d58 100644
--- a/core/java/android/nfc/NfcAdapter.java
+++ b/core/java/android/nfc/NfcAdapter.java
@@ -584,17 +584,138 @@
         }
     }
 
-    //TODO: make sure NFC service has permission for URI
-    //TODO: see if we will eventually support multiple URIs
-    //TODO: javadoc
+    /**
+     * Set one or more {@link Uri}s to send using Android Beam (TM). Every
+     * Uri you provide must have either scheme 'file' or scheme 'content'.
+     *
+     * <p>For the data provided through this method, Android Beam tries to
+     * switch to alternate transports such as Bluetooth to achieve a fast
+     * transfer speed. Hence this method is very suitable
+     * for transferring large files such as pictures or songs.
+     *
+     * <p>The receiving side will store the content of each Uri in
+     * a file and present a notification to the user to open the file
+     * with a {@link android.content.Intent} with action
+     * {@link android.content.Intent#ACTION_VIEW}.
+     * If multiple URIs are sent, the {@link android.content.Intent} will refer
+     * to the first of the stored files.
+     *
+     * <p>This method may be called at any time before {@link Activity#onDestroy},
+     * but the URI(s) are only made available for Android Beam when the
+     * specified activity(s) are in resumed (foreground) state. The recommended
+     * approach is to call this method during your Activity's
+     * {@link Activity#onCreate} - see sample
+     * code below. This method does not immediately perform any I/O or blocking work,
+     * so is safe to call on your main thread.
+     *
+     * <p>{@link #setBeamPushUris} and {@link #setBeamPushUrisCallback}
+     * have priority over both {@link #setNdefPushMessage} and
+     * {@link #setNdefPushMessageCallback}.
+     *
+     * <p>If {@link #setBeamPushUris} is called with a null Uri array,
+     * and/or {@link #setBeamPushUrisCallback} is called with a null callback,
+     * then the Uri push will be completely disabled for the specified activity(s).
+     *
+     * <p>Code example:
+     * <pre>
+     * protected void onCreate(Bundle savedInstanceState) {
+     *     super.onCreate(savedInstanceState);
+     *     NfcAdapter nfcAdapter = NfcAdapter.getDefaultAdapter(this);
+     *     if (nfcAdapter == null) return;  // NFC not available on this device
+     *     nfcAdapter.setBeamPushUris(new Uri[] {uri1, uri2}, this);
+     * }
+     * </pre>
+     * And that is it. Only one call per activity is necessary. The Android
+     * OS will automatically release its references to the Uri(s) and the
+     * Activity object when it is destroyed if you follow this pattern.
+     *
+     * <p>If your Activity wants to dynamically supply Uri(s),
+     * then set a callback using {@link #setBeamPushUrisCallback} instead
+     * of using this method.
+     *
+     * <p class="note">Do not pass in an Activity that has already been through
+     * {@link Activity#onDestroy}. This is guaranteed if you call this API
+     * during {@link Activity#onCreate}.
+     *
+     * <p class="note">Requires the {@link android.Manifest.permission#NFC} permission.
+     *
+     * @param uris an array of Uri(s) to push over Android Beam
+     * @param activity activity for which the Uri(s) will be pushed
+     */
     public void setBeamPushUris(Uri[] uris, Activity activity) {
         if (activity == null) {
             throw new NullPointerException("activity cannot be null");
         }
+        if (uris != null) {
+            for (Uri uri : uris) {
+                if (uri == null) throw new NullPointerException("Uri not " +
+                        "allowed to be null");
+                String scheme = uri.getScheme();
+                if (scheme == null || (!scheme.equalsIgnoreCase("file") &&
+                        !scheme.equalsIgnoreCase("content"))) {
+                    throw new IllegalArgumentException("URI needs to have " +
+                            "either scheme file or scheme content");
+                }
+            }
+        }
         mNfcActivityManager.setNdefPushContentUri(activity, uris);
     }
 
-    // TODO javadoc
+    /**
+     * Set a callback that will dynamically generate one or more {@link Uri}s
+     * to send using Android Beam (TM). Every Uri the callback provides
+     * must have either scheme 'file' or scheme 'content'.
+     *
+     * <p>For the data provided through this callback, Android Beam tries to
+     * switch to alternate transports such as Bluetooth to achieve a fast
+     * transfer speed. Hence this method is very suitable
+     * for transferring large files such as pictures or songs.
+     *
+     * <p>The receiving side will store the content of each Uri in
+     * a file and present a notification to the user to open the file
+     * with a {@link android.content.Intent} with action
+     * {@link android.content.Intent#ACTION_VIEW}.
+     * If multiple URIs are sent, the {@link android.content.Intent} will refer
+     * to the first of the stored files.
+     *
+     * <p>This method may be called at any time before {@link Activity#onDestroy},
+     * but the URI(s) are only made available for Android Beam when the
+     * specified activity(s) are in resumed (foreground) state. The recommended
+     * approach is to call this method during your Activity's
+     * {@link Activity#onCreate} - see sample
+     * code below. This method does not immediately perform any I/O or blocking work,
+     * so is safe to call on your main thread.
+     *
+     * <p>{@link #setBeamPushUris} and {@link #setBeamPushUrisCallback}
+     * have priority over both {@link #setNdefPushMessage} and
+     * {@link #setNdefPushMessageCallback}.
+     *
+     * <p>If {@link #setBeamPushUris} is called with a null Uri array,
+     * and/or {@link #setBeamPushUrisCallback} is called with a null callback,
+     * then the Uri push will be completely disabled for the specified activity(s).
+     *
+     * <p>Code example:
+     * <pre>
+     * protected void onCreate(Bundle savedInstanceState) {
+     *     super.onCreate(savedInstanceState);
+     *     NfcAdapter nfcAdapter = NfcAdapter.getDefaultAdapter(this);
+     *     if (nfcAdapter == null) return;  // NFC not available on this device
+     *     nfcAdapter.setBeamPushUrisCallback(callback, this);
+     * }
+     * </pre>
+     * And that is it. Only one call per activity is necessary. The Android
+     * OS will automatically release its references to the Uri(s) and the
+     * Activity object when it is destroyed if you follow this pattern.
+     *
+     * <p class="note">Do not pass in an Activity that has already been through
+     * {@link Activity#onDestroy}. This is guaranteed if you call this API
+     * during {@link Activity#onCreate}.
+     *
+     * <p class="note">Requires the {@link android.Manifest.permission#NFC} permission.
+     *
+     * @param callback callback, or null to disable
+     * @param activity activity for which the Uri(s) will be pushed
+     */
     public void setBeamPushUrisCallback(CreateBeamUrisCallback callback, Activity activity) {
         if (activity == null) {
             throw new NullPointerException("activity cannot be null");
@@ -663,6 +784,10 @@
      * {@link Activity#onDestroy}. This is guaranteed if you call this API
      * during {@link Activity#onCreate}.
      *
+     * <p class="note">For sending large content such as pictures and songs,
+     * consider using {@link #setBeamPushUris}, which switches to alternate transports
+     * such as Bluetooth to achieve a fast transfer rate.
+     *
      * <p class="note">Requires the {@link android.Manifest.permission#NFC} permission.
      *
      * @param message NDEF message to push over NFC, or null to disable
@@ -753,7 +878,9 @@
      * <p class="note">Do not pass in an Activity that has already been through
      * {@link Activity#onDestroy}. This is guaranteed if you call this API
      * during {@link Activity#onCreate}.
-     *
+     * <p class="note">For sending large content such as pictures and songs,
+     * consider using {@link #setBeamPushUris}, which switches to alternate transports
+     * such as Bluetooth to achieve a fast transfer rate.
      * <p class="note">Requires the {@link android.Manifest.permission#NFC} permission.
      *
      * @param callback callback, or null to disable
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index d62f513..d94275b 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -691,13 +691,6 @@
          */
         public static final int FLAG_NEEDS_MENU_KEY = 0x08000000;
 
-        /** Window flag: *sigh* The lock screen wants to continue running its
-         * animation while it is fading.  A kind-of hack to allow this.  Maybe
-         * in the future we just make this the default behavior.
-         *
-         * {@hide} */
-        public static final int FLAG_KEEP_SURFACE_WHILE_ANIMATING = 0x10000000;
-        
         /** Window flag: special flag to limit the size of the window to be
          * original size ([320x480] x density). Used to create window for applications
          * running under compatibility mode.
diff --git a/core/java/android/webkit/WebViewClassic.java b/core/java/android/webkit/WebViewClassic.java
index ee24e5e..add0fbb 100644
--- a/core/java/android/webkit/WebViewClassic.java
+++ b/core/java/android/webkit/WebViewClassic.java
@@ -100,7 +100,6 @@
 import android.webkit.WebViewCore.EventHub;
 import android.webkit.WebViewCore.TextFieldInitData;
 import android.webkit.WebViewCore.TextSelectionData;
-import android.webkit.WebViewCore.TouchHighlightData;
 import android.webkit.WebViewCore.WebKitHitTest;
 import android.widget.AbsoluteLayout;
 import android.widget.Adapter;
@@ -274,6 +273,7 @@
                 newCursorPosition -= text.length() - limitedText.length();
             }
             super.setComposingText(limitedText, newCursorPosition);
+            updateSelection();
             if (limitedText != text) {
                 restartInput();
                 int lastCaret = start + limitedText.length();
@@ -286,19 +286,44 @@
         @Override
         public boolean commitText(CharSequence text, int newCursorPosition) {
             setComposingText(text, newCursorPosition);
-            int cursorPosition = Selection.getSelectionEnd(getEditable());
-            setComposingRegion(cursorPosition, cursorPosition);
+            finishComposingText();
             return true;
         }
 
         @Override
         public boolean deleteSurroundingText(int leftLength, int rightLength) {
-            Editable editable = getEditable();
-            int cursorPosition = Selection.getSelectionEnd(editable);
-            int startDelete = Math.max(0, cursorPosition - leftLength);
-            int endDelete = Math.min(editable.length(),
-                    cursorPosition + rightLength);
-            setNewText(startDelete, endDelete, "");
+            // This code is from BaseInputConnection#deleteSurroundText.
+            // We have to delete the same text in webkit.
+            Editable content = getEditable();
+            int a = Selection.getSelectionStart(content);
+            int b = Selection.getSelectionEnd(content);
+
+            if (a > b) {
+                int tmp = a;
+                a = b;
+                b = tmp;
+            }
+
+            int ca = getComposingSpanStart(content);
+            int cb = getComposingSpanEnd(content);
+            if (cb < ca) {
+                int tmp = ca;
+                ca = cb;
+                cb = tmp;
+            }
+            if (ca != -1 && cb != -1) {
+                if (ca < a) a = ca;
+                if (cb > b) b = cb;
+            }
+
+            int endDelete = Math.min(content.length(), b + rightLength);
+            if (endDelete > b) {
+                setNewText(b, endDelete, "");
+            }
+            int startDelete = Math.max(0, a - leftLength);
+            if (startDelete < a) {
+                setNewText(startDelete, a, "");
+            }
             return super.deleteSurroundingText(leftLength, rightLength);
         }
 
@@ -411,6 +436,46 @@
             outAttrs.imeOptions = mImeOptions;
             outAttrs.hintText = mHint;
             outAttrs.initialCapsMode = getCursorCapsMode(InputType.TYPE_CLASS_TEXT);
+
+            Editable editable = getEditable();
+            int selectionStart = Selection.getSelectionStart(editable);
+            int selectionEnd = Selection.getSelectionEnd(editable);
+            if (selectionStart < 0 || selectionEnd < 0) {
+                selectionStart = editable.length();
+                selectionEnd = selectionStart;
+            }
+            outAttrs.initialSelStart = selectionStart;
+            outAttrs.initialSelEnd = selectionEnd;
+        }
+
+        @Override
+        public boolean setSelection(int start, int end) {
+            boolean result = super.setSelection(start, end);
+            updateSelection();
+            return result;
+        }
+
+        @Override
+        public boolean setComposingRegion(int start, int end) {
+            boolean result = super.setComposingRegion(start, end);
+            updateSelection();
+            return result;
+        }
+
+        /**
+         * Send the selection and composing spans to the IME.
+         */
+        private void updateSelection() {
+            Editable editable = getEditable();
+            int selectionStart = Selection.getSelectionStart(editable);
+            int selectionEnd = Selection.getSelectionEnd(editable);
+            int composingStart = getComposingSpanStart(editable);
+            int composingEnd = getComposingSpanEnd(editable);
+            InputMethodManager imm = InputMethodManager.peekInstance();
+            if (imm != null) {
+                imm.updateSelection(mWebView, selectionStart, selectionEnd,
+                        composingStart, composingEnd);
+            }
         }
 
         /**
@@ -4965,6 +5030,7 @@
 
     private void adjustSelectionCursors() {
         if (mIsCaretSelection) {
+            syncSelectionCursors();
             return; // no need to swap left and right handles.
         }
 
diff --git a/core/res/res/drawable-hdpi/switch_thumb_activated_holo_dark.9.png b/core/res/res/drawable-hdpi/switch_thumb_activated_holo_dark.9.png
index 2fc475b..9c5147e 100644
--- a/core/res/res/drawable-hdpi/switch_thumb_activated_holo_dark.9.png
+++ b/core/res/res/drawable-hdpi/switch_thumb_activated_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/switch_thumb_activated_holo_light.9.png b/core/res/res/drawable-hdpi/switch_thumb_activated_holo_light.9.png
index 5adecf1..9c5147e 100644
--- a/core/res/res/drawable-hdpi/switch_thumb_activated_holo_light.9.png
+++ b/core/res/res/drawable-hdpi/switch_thumb_activated_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/switch_thumb_disabled_holo_dark.9.png b/core/res/res/drawable-hdpi/switch_thumb_disabled_holo_dark.9.png
index 457fa84..a257e26 100644
--- a/core/res/res/drawable-hdpi/switch_thumb_disabled_holo_dark.9.png
+++ b/core/res/res/drawable-hdpi/switch_thumb_disabled_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/switch_thumb_disabled_holo_light.9.png b/core/res/res/drawable-hdpi/switch_thumb_disabled_holo_light.9.png
index c3cfc29..a257e26 100644
--- a/core/res/res/drawable-hdpi/switch_thumb_disabled_holo_light.9.png
+++ b/core/res/res/drawable-hdpi/switch_thumb_disabled_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/switch_thumb_holo_dark.9.png b/core/res/res/drawable-hdpi/switch_thumb_holo_dark.9.png
index d0e1806..dd999d6 100644
--- a/core/res/res/drawable-hdpi/switch_thumb_holo_dark.9.png
+++ b/core/res/res/drawable-hdpi/switch_thumb_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/switch_thumb_holo_light.9.png b/core/res/res/drawable-hdpi/switch_thumb_holo_light.9.png
index c30506d..dd999d6 100644
--- a/core/res/res/drawable-hdpi/switch_thumb_holo_light.9.png
+++ b/core/res/res/drawable-hdpi/switch_thumb_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/switch_thumb_pressed_holo_dark.9.png b/core/res/res/drawable-hdpi/switch_thumb_pressed_holo_dark.9.png
index 9106687..ea54380 100644
--- a/core/res/res/drawable-hdpi/switch_thumb_pressed_holo_dark.9.png
+++ b/core/res/res/drawable-hdpi/switch_thumb_pressed_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/switch_thumb_pressed_holo_light.9.png b/core/res/res/drawable-hdpi/switch_thumb_pressed_holo_light.9.png
index 2bdda56..ea54380 100644
--- a/core/res/res/drawable-hdpi/switch_thumb_pressed_holo_light.9.png
+++ b/core/res/res/drawable-hdpi/switch_thumb_pressed_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/switch_thumb_activated_holo_dark.9.png b/core/res/res/drawable-mdpi/switch_thumb_activated_holo_dark.9.png
index 0787d16..3d7c236 100644
--- a/core/res/res/drawable-mdpi/switch_thumb_activated_holo_dark.9.png
+++ b/core/res/res/drawable-mdpi/switch_thumb_activated_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/switch_thumb_activated_holo_light.9.png b/core/res/res/drawable-mdpi/switch_thumb_activated_holo_light.9.png
index 0157e68..3d7c236 100644
--- a/core/res/res/drawable-mdpi/switch_thumb_activated_holo_light.9.png
+++ b/core/res/res/drawable-mdpi/switch_thumb_activated_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/switch_thumb_disabled_holo_dark.9.png b/core/res/res/drawable-mdpi/switch_thumb_disabled_holo_dark.9.png
index 51b14d0..82f05d6 100644
--- a/core/res/res/drawable-mdpi/switch_thumb_disabled_holo_dark.9.png
+++ b/core/res/res/drawable-mdpi/switch_thumb_disabled_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/switch_thumb_disabled_holo_light.9.png b/core/res/res/drawable-mdpi/switch_thumb_disabled_holo_light.9.png
index d68568a..82f05d6 100644
--- a/core/res/res/drawable-mdpi/switch_thumb_disabled_holo_light.9.png
+++ b/core/res/res/drawable-mdpi/switch_thumb_disabled_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/switch_thumb_holo_dark.9.png b/core/res/res/drawable-mdpi/switch_thumb_holo_dark.9.png
index 6bf153a..9bc7a68 100644
--- a/core/res/res/drawable-mdpi/switch_thumb_holo_dark.9.png
+++ b/core/res/res/drawable-mdpi/switch_thumb_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/switch_thumb_holo_light.9.png b/core/res/res/drawable-mdpi/switch_thumb_holo_light.9.png
index 0d98983..9bc7a68 100644
--- a/core/res/res/drawable-mdpi/switch_thumb_holo_light.9.png
+++ b/core/res/res/drawable-mdpi/switch_thumb_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/switch_thumb_pressed_holo_dark.9.png b/core/res/res/drawable-mdpi/switch_thumb_pressed_holo_dark.9.png
index 3cee7b8..670dc2e 100644
--- a/core/res/res/drawable-mdpi/switch_thumb_pressed_holo_dark.9.png
+++ b/core/res/res/drawable-mdpi/switch_thumb_pressed_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/switch_thumb_pressed_holo_light.9.png b/core/res/res/drawable-mdpi/switch_thumb_pressed_holo_light.9.png
index 43a7c4c..670dc2e 100644
--- a/core/res/res/drawable-mdpi/switch_thumb_pressed_holo_light.9.png
+++ b/core/res/res/drawable-mdpi/switch_thumb_pressed_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/switch_thumb_activated_holo_dark.9.png b/core/res/res/drawable-xhdpi/switch_thumb_activated_holo_dark.9.png
index a0e6b20..ca48bd8 100644
--- a/core/res/res/drawable-xhdpi/switch_thumb_activated_holo_dark.9.png
+++ b/core/res/res/drawable-xhdpi/switch_thumb_activated_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/switch_thumb_activated_holo_light.9.png b/core/res/res/drawable-xhdpi/switch_thumb_activated_holo_light.9.png
index 88235fe..ca48bd8 100644
--- a/core/res/res/drawable-xhdpi/switch_thumb_activated_holo_light.9.png
+++ b/core/res/res/drawable-xhdpi/switch_thumb_activated_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/switch_thumb_disabled_holo_dark.9.png b/core/res/res/drawable-xhdpi/switch_thumb_disabled_holo_dark.9.png
index 04fb9a1..c3d80f0 100644
--- a/core/res/res/drawable-xhdpi/switch_thumb_disabled_holo_dark.9.png
+++ b/core/res/res/drawable-xhdpi/switch_thumb_disabled_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/switch_thumb_disabled_holo_light.9.png b/core/res/res/drawable-xhdpi/switch_thumb_disabled_holo_light.9.png
index 06a14f3..c3d80f0 100644
--- a/core/res/res/drawable-xhdpi/switch_thumb_disabled_holo_light.9.png
+++ b/core/res/res/drawable-xhdpi/switch_thumb_disabled_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/switch_thumb_holo_dark.9.png b/core/res/res/drawable-xhdpi/switch_thumb_holo_dark.9.png
index af7d631..df236df 100644
--- a/core/res/res/drawable-xhdpi/switch_thumb_holo_dark.9.png
+++ b/core/res/res/drawable-xhdpi/switch_thumb_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/switch_thumb_holo_light.9.png b/core/res/res/drawable-xhdpi/switch_thumb_holo_light.9.png
index d6ab3ea..df236df 100644
--- a/core/res/res/drawable-xhdpi/switch_thumb_holo_light.9.png
+++ b/core/res/res/drawable-xhdpi/switch_thumb_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/switch_thumb_pressed_holo_dark.9.png b/core/res/res/drawable-xhdpi/switch_thumb_pressed_holo_dark.9.png
index 5a8e807..4acb32b 100644
--- a/core/res/res/drawable-xhdpi/switch_thumb_pressed_holo_dark.9.png
+++ b/core/res/res/drawable-xhdpi/switch_thumb_pressed_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/switch_thumb_pressed_holo_light.9.png b/core/res/res/drawable-xhdpi/switch_thumb_pressed_holo_light.9.png
index 392f3dc..4acb32b 100644
--- a/core/res/res/drawable-xhdpi/switch_thumb_pressed_holo_light.9.png
+++ b/core/res/res/drawable-xhdpi/switch_thumb_pressed_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable/switch_track_holo_dark.xml b/core/res/res/drawable/switch_track_holo_dark.xml
index c9a940d..5f796c1 100644
--- a/core/res/res/drawable/switch_track_holo_dark.xml
+++ b/core/res/res/drawable/switch_track_holo_dark.xml
@@ -15,7 +15,6 @@
 -->
 
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:state_enabled="false" android:drawable="@drawable/switch_bg_disabled_holo_dark" />
     <item android:state_focused="true"  android:drawable="@drawable/switch_bg_focused_holo_dark" />
     <item                               android:drawable="@drawable/switch_bg_holo_dark" />
 </selector>
diff --git a/core/res/res/drawable/switch_track_holo_light.xml b/core/res/res/drawable/switch_track_holo_light.xml
index 98e53b5..39bee37 100644
--- a/core/res/res/drawable/switch_track_holo_light.xml
+++ b/core/res/res/drawable/switch_track_holo_light.xml
@@ -15,7 +15,6 @@
 -->
 
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:state_enabled="false" android:drawable="@drawable/switch_bg_disabled_holo_light" />
     <item android:state_focused="true"  android:drawable="@drawable/switch_bg_focused_holo_light" />
     <item                               android:drawable="@drawable/switch_bg_holo_light" />
 </selector>
diff --git a/media/java/android/media/AudioService.java b/media/java/android/media/AudioService.java
index d165b5e..aa29444 100644
--- a/media/java/android/media/AudioService.java
+++ b/media/java/android/media/AudioService.java
@@ -3699,38 +3699,15 @@
     }
 
     /**
-     * The minimum duration during which a user must press to trigger voice-based interactions
-     */
-    private final static int MEDIABUTTON_LONG_PRESS_DURATION_MS = 300;
-    /**
-     * The different states of the state machine to handle the launch of voice-based interactions,
-     * stored in mVoiceButtonState.
-     */
-    private final static int VOICEBUTTON_STATE_IDLE = 0;
-    private final static int VOICEBUTTON_STATE_DOWN = 1;
-    private final static int VOICEBUTTON_STATE_DOWN_IGNORE_NEW = 2;
-    /**
-     * The different actions after state transitions on mVoiceButtonState.
+     * The different actions performed in response to a voice button key event.
      */
     private final static int VOICEBUTTON_ACTION_DISCARD_CURRENT_KEY_PRESS = 1;
     private final static int VOICEBUTTON_ACTION_START_VOICE_INPUT = 2;
     private final static int VOICEBUTTON_ACTION_SIMULATE_KEY_PRESS = 3;
 
     private final Object mVoiceEventLock = new Object();
-    private int mVoiceButtonState = VOICEBUTTON_STATE_IDLE;
-    private long mVoiceButtonDownTime = 0;
-
-    /**
-     * Log an error when an unexpected action is encountered in the state machine to filter
-     * key events.
-     * @param keyAction the unexpected action of the key event being filtered
-     * @param stateName the string corresponding to the state in which the error occurred
-     */
-    private static void logErrorForKeyAction(int keyAction, String stateName) {
-        Log.e(TAG, "unexpected action "
-                + KeyEvent.actionToString(keyAction)
-                + " in " + stateName + " state");
-    }
+    private boolean mVoiceButtonDown;
+    private boolean mVoiceButtonHandled;
 
     /**
      * Filter key events that may be used for voice-based interactions
@@ -3740,67 +3717,32 @@
      *     is dispatched.
      */
     private void filterVoiceInputKeyEvent(KeyEvent keyEvent, boolean needWakeLock) {
+        if (DEBUG_RC) {
+            Log.v(TAG, "voice input key event: " + keyEvent + ", needWakeLock=" + needWakeLock);
+        }
+
         int voiceButtonAction = VOICEBUTTON_ACTION_DISCARD_CURRENT_KEY_PRESS;
         int keyAction = keyEvent.getAction();
         synchronized (mVoiceEventLock) {
-            // state machine on mVoiceButtonState
-            switch (mVoiceButtonState) {
-
-                case VOICEBUTTON_STATE_IDLE:
-                    if (keyAction == KeyEvent.ACTION_DOWN) {
-                        mVoiceButtonDownTime = keyEvent.getDownTime();
-                        // valid state transition
-                        mVoiceButtonState = VOICEBUTTON_STATE_DOWN;
-                    } else if (keyAction == KeyEvent.ACTION_UP) {
-                        // no state transition
-                        // action is still VOICEBUTTON_ACTION_DISCARD_CURRENT_KEY_PRESS
-                    } else {
-                        logErrorForKeyAction(keyAction, "VOICEBUTTON_STATE_IDLE");
+            if (keyAction == KeyEvent.ACTION_DOWN) {
+                if (keyEvent.getRepeatCount() == 0) {
+                    // initial down
+                    mVoiceButtonDown = true;
+                    mVoiceButtonHandled = false;
+                } else if (mVoiceButtonDown && !mVoiceButtonHandled
+                        && (keyEvent.getFlags() & KeyEvent.FLAG_LONG_PRESS) != 0) {
+                    // long-press, start voice-based interactions
+                    mVoiceButtonHandled = true;
+                    voiceButtonAction = VOICEBUTTON_ACTION_START_VOICE_INPUT;
+                }
+            } else if (keyAction == KeyEvent.ACTION_UP) {
+                if (mVoiceButtonDown) {
+                    // voice button up
+                    mVoiceButtonDown = false;
+                    if (!mVoiceButtonHandled && !keyEvent.isCanceled()) {
+                        voiceButtonAction = VOICEBUTTON_ACTION_SIMULATE_KEY_PRESS;
                     }
-                    break;
-
-                case VOICEBUTTON_STATE_DOWN:
-                    if ((keyEvent.getEventTime() - mVoiceButtonDownTime)
-                            >= MEDIABUTTON_LONG_PRESS_DURATION_MS) {
-                        // press was long enough, start voice-based interactions, regardless of
-                        //   whether this was a DOWN or UP key event
-                        voiceButtonAction = VOICEBUTTON_ACTION_START_VOICE_INPUT;
-                        if (keyAction == KeyEvent.ACTION_UP) {
-                            // done tracking the key press, so transition back to idle state
-                            mVoiceButtonState = VOICEBUTTON_STATE_IDLE;
-                        } else if (keyAction == KeyEvent.ACTION_DOWN) {
-                            // no need to observe the upcoming key events
-                            mVoiceButtonState = VOICEBUTTON_STATE_DOWN_IGNORE_NEW;
-                        } else {
-                            logErrorForKeyAction(keyAction, "VOICEBUTTON_STATE_DOWN");
-                        }
-                    } else {
-                        if (keyAction == KeyEvent.ACTION_UP) {
-                            // press wasn't long enough, simulate complete key press
-                            voiceButtonAction = VOICEBUTTON_ACTION_SIMULATE_KEY_PRESS;
-                            // not tracking the key press anymore, so transition back to idle state
-                            mVoiceButtonState = VOICEBUTTON_STATE_IDLE;
-                        } else if (keyAction == KeyEvent.ACTION_DOWN) {
-                            // no state transition
-                            // action is still VOICEBUTTON_ACTION_DISCARD_CURRENT_KEY_PRESS
-                        } else {
-                            logErrorForKeyAction(keyAction, "VOICEBUTTON_STATE_DOWN");
-                        }
-                    }
-                    break;
-
-                case VOICEBUTTON_STATE_DOWN_IGNORE_NEW:
-                    if (keyAction == KeyEvent.ACTION_UP) {
-                        // done tracking the key press, so transition back to idle state
-                        mVoiceButtonState = VOICEBUTTON_STATE_IDLE;
-                        // action is still VOICEBUTTON_ACTION_DISCARD_CURRENT_KEY_PRESS
-                    } else if (keyAction == KeyEvent.ACTION_DOWN) {
-                        // no state transition: we've already launched voice-based interactions
-                        // action is still VOICEBUTTON_ACTION_DISCARD_CURRENT_KEY_PRESS
-                    } else  {
-                        logErrorForKeyAction(keyAction, "VOICEBUTTON_STATE_DOWN_IGNORE_NEW");
-                    }
-                    break;
+                }
             }
         }//synchronized (mVoiceEventLock)
 
diff --git a/policy/src/com/android/internal/policy/impl/KeyguardViewManager.java b/policy/src/com/android/internal/policy/impl/KeyguardViewManager.java
index 7f432bf..504bb63 100644
--- a/policy/src/com/android/internal/policy/impl/KeyguardViewManager.java
+++ b/policy/src/com/android/internal/policy/impl/KeyguardViewManager.java
@@ -117,7 +117,6 @@
             final int stretch = ViewGroup.LayoutParams.MATCH_PARENT;
             int flags = WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN
                     | WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER
-                    | WindowManager.LayoutParams.FLAG_KEEP_SURFACE_WHILE_ANIMATING
                     | WindowManager.LayoutParams.FLAG_SLIPPERY
                     /*| WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
                     | WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR*/ ;
diff --git a/services/java/com/android/server/WifiService.java b/services/java/com/android/server/WifiService.java
index b1558c7..1f03d17 100644
--- a/services/java/com/android/server/WifiService.java
+++ b/services/java/com/android/server/WifiService.java
@@ -376,11 +376,7 @@
                     @Override
                     public void onReceive(Context context, Intent intent) {
                         mAirplaneModeOn.set(isAirplaneModeOn());
-                        /* On airplane mode disable, restore wifi state if necessary */
-                        if (!mAirplaneModeOn.get() && (testAndClearWifiSavedState() ||
-                            mPersistWifiState.get() == WIFI_ENABLED_AIRPLANE_OVERRIDE)) {
-                                persistWifiState(true);
-                        }
+                        handleAirplaneModeToggled(mAirplaneModeOn.get());
                         updateWifiState();
                     }
                 },
@@ -447,7 +443,10 @@
         boolean wifiEnabled = shouldWifiBeEnabled() || testAndClearWifiSavedState();
         Slog.i(TAG, "WifiService starting up with Wi-Fi " +
                 (wifiEnabled ? "enabled" : "disabled"));
-        setWifiEnabled(wifiEnabled);
+
+        // If we are already disabled (could be due to airplane mode), avoid changing persist
+        // state here
+        if (wifiEnabled) setWifiEnabled(wifiEnabled);
 
         mWifiWatchdogStateMachine = WifiWatchdogStateMachine.
                makeWifiWatchdogStateMachine(mContext);
@@ -485,26 +484,43 @@
         }
     }
 
-    private void persistWifiState(boolean enabled) {
-        final ContentResolver cr = mContext.getContentResolver();
-        boolean airplane = mAirplaneModeOn.get() && isAirplaneToggleable();
-        if (enabled) {
-            if (airplane) {
-                mPersistWifiState.set(WIFI_ENABLED_AIRPLANE_OVERRIDE);
+    private void handleWifiToggled(boolean wifiEnabled) {
+        boolean airplaneEnabled = mAirplaneModeOn.get() && isAirplaneToggleable();
+        if (wifiEnabled) {
+            if (airplaneEnabled) {
+                persistWifiState(WIFI_ENABLED_AIRPLANE_OVERRIDE);
             } else {
-                mPersistWifiState.set(WIFI_ENABLED);
+                persistWifiState(WIFI_ENABLED);
             }
         } else {
-            if (airplane) {
-                mPersistWifiState.set(WIFI_DISABLED_AIRPLANE_ON);
-            } else {
-                mPersistWifiState.set(WIFI_DISABLED);
-            }
+            // When wifi state is disabled, we do not care
+            // if airplane mode is on or not. The scenario of
+            // wifi being disabled due to airplane mode being turned on
+            // is handled handleAirplaneModeToggled()
+            persistWifiState(WIFI_DISABLED);
         }
-
-        Settings.Secure.putInt(cr, Settings.Secure.WIFI_ON, mPersistWifiState.get());
     }
 
+    private void handleAirplaneModeToggled(boolean airplaneEnabled) {
+        if (airplaneEnabled) {
+            // Wifi disabled due to airplane on
+            if (mWifiEnabled) {
+                persistWifiState(WIFI_DISABLED_AIRPLANE_ON);
+            }
+        } else {
+            /* On airplane mode disable, restore wifi state if necessary */
+            if (testAndClearWifiSavedState() ||
+                    mPersistWifiState.get() == WIFI_ENABLED_AIRPLANE_OVERRIDE) {
+                persistWifiState(WIFI_ENABLED);
+            }
+        }
+    }
+
+    private void persistWifiState(int state) {
+        final ContentResolver cr = mContext.getContentResolver();
+        mPersistWifiState.set(state);
+        Settings.Secure.putInt(cr, Settings.Secure.WIFI_ON, state);
+    }
 
     /**
      * see {@link android.net.wifi.WifiManager#pingSupplicant()}
@@ -578,12 +594,9 @@
          * only CHANGE_WIFI_STATE is enforced
          */
 
-        /* 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);
-        }
+        long ident = Binder.clearCallingIdentity();
+        handleWifiToggled(enable);
+        Binder.restoreCallingIdentity(ident);
 
         if (enable) {
             if (!mIsReceiverRegistered) {
diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java
index b3ac6f1..f460f9b 100755
--- a/services/java/com/android/server/wm/WindowManagerService.java
+++ b/services/java/com/android/server/wm/WindowManagerService.java
@@ -1173,8 +1173,7 @@
             if (DEBUG_INPUT_METHOD) {
                 Slog.i(TAG, "isVisibleOrAdding " + w + ": " + w.isVisibleOrAdding());
                 if (!w.isVisibleOrAdding()) {
-                    Slog.i(TAG, "  mSurface=" + w.mWinAnimator.mSurface + " reportDestroy="
-                            + w.mWinAnimator.mReportDestroySurface
+                    Slog.i(TAG, "  mSurface=" + w.mWinAnimator.mSurface
                             + " relayoutCalled=" + w.mRelayoutCalled + " viewVis=" + w.mViewVisibility
                             + " policyVis=" + w.mPolicyVisibility + " attachHid=" + w.mAttachedHidden
                             + " exiting=" + w.mExiting + " destroying=" + w.mDestroying);
@@ -2651,7 +2650,7 @@
             int requestedHeight, int viewVisibility, int flags,
             Rect outFrame, Rect outContentInsets,
             Rect outVisibleInsets, Configuration outConfig, Surface outSurface) {
-        boolean displayed = false;
+        boolean toBeDisplayed = false;
         boolean inTouchMode;
         boolean configChanged;
         boolean surfaceChanged = false;
@@ -2754,7 +2753,7 @@
             }
             if (viewVisibility == View.VISIBLE &&
                     (win.mAppToken == null || !win.mAppToken.clientHidden)) {
-                displayed = !win.isVisibleLw();
+                toBeDisplayed = !win.isVisibleLw();
                 if (win.mExiting) {
                     winAnimator.cancelExitAnimationForNextAnimationLocked();
                     win.mExiting = false;
@@ -2766,7 +2765,7 @@
                 if (oldVisibility == View.GONE) {
                     winAnimator.mEnterAnimationPending = true;
                 }
-                if (displayed) {
+                if (toBeDisplayed) {
                     if (win.isDrawnLw() && okToDisplay()) {
                         winAnimator.applyEnterAnimationLocked();
                     }
@@ -2792,7 +2791,7 @@
                 if ((attrChanges&WindowManager.LayoutParams.FORMAT_CHANGED) != 0) {
                     // To change the format, we need to re-build the surface.
                     winAnimator.destroySurfaceLocked();
-                    displayed = true;
+                    toBeDisplayed = true;
                     surfaceChanged = true;
                 }
                 try {
@@ -2802,8 +2801,6 @@
                     Surface surface = winAnimator.createSurfaceLocked();
                     if (surface != null) {
                         outSurface.copyFrom(surface);
-                        winAnimator.mReportDestroySurface = false;
-                        winAnimator.mSurfacePendingDestroy = false;
                         if (SHOW_TRANSACTIONS) Slog.i(TAG,
                                 "  OUT SURFACE " + outSurface + ": copied");
                     } else {
@@ -2820,7 +2817,7 @@
                     Binder.restoreCallingIdentity(origId);
                     return 0;
                 }
-                if (displayed) {
+                if (toBeDisplayed) {
                     focusMayChange = true;
                 }
                 if (win.mAttrs.type == TYPE_INPUT_METHOD
@@ -2845,11 +2842,10 @@
                 winAnimator.mEnterAnimationPending = false;
                 if (winAnimator.mSurface != null) {
                     if (DEBUG_VISIBILITY) Slog.i(TAG, "Relayout invis " + win
-                            + ": mExiting=" + win.mExiting
-                            + " mSurfacePendingDestroy=" + winAnimator.mSurfacePendingDestroy);
+                            + ": mExiting=" + win.mExiting);
                     // If we are not currently running the exit animation, we
                     // need to see about starting one.
-                    if (!win.mExiting || winAnimator.mSurfacePendingDestroy) {
+                    if (!win.mExiting) {
                         surfaceChanged = true;
                         // Try starting an animation; if there isn't one, we
                         // can destroy the surface right away.
@@ -2857,7 +2853,7 @@
                         if (win.mAttrs.type == TYPE_APPLICATION_STARTING) {
                             transit = WindowManagerPolicy.TRANSIT_PREVIEW_DONE;
                         }
-                        if (!winAnimator.mSurfacePendingDestroy && win.isWinVisibleLw() &&
+                        if (win.isWinVisibleLw() &&
                                 winAnimator.applyAnimationLocked(transit, false)) {
                             focusMayChange = true;
                             win.mExiting = true;
@@ -2880,22 +2876,8 @@
                     }
                 }
 
-                if (winAnimator.mSurface == null || (win.getAttrs().flags
-                        & WindowManager.LayoutParams.FLAG_KEEP_SURFACE_WHILE_ANIMATING) == 0
-                        || winAnimator.mSurfacePendingDestroy) {
-                    // We could be called from a local process, which
-                    // means outSurface holds its current surface.  Ensure the
-                    // surface object is cleared, but we don't necessarily want
-                    // it actually destroyed at this point.
-                    winAnimator.mSurfacePendingDestroy = false;
-                    outSurface.release();
-                    if (DEBUG_VISIBILITY) Slog.i(TAG, "Releasing surface in: " + win);
-                } else if (winAnimator.mSurface != null) {
-                    if (DEBUG_VISIBILITY) Slog.i(TAG,
-                            "Keeping surface, will report destroy: " + win);
-                    winAnimator.mReportDestroySurface = true;
-                    outSurface.copyFrom(winAnimator.mSurface);
-                }
+                outSurface.release();
+                if (DEBUG_VISIBILITY) Slog.i(TAG, "Releasing surface in: " + win);
             }
 
             if (focusMayChange) {
@@ -2912,7 +2894,7 @@
             boolean assignLayers = false;
 
             if (imMayMove) {
-                if (moveInputMethodWindowsIfNeededLocked(false) || displayed) {
+                if (moveInputMethodWindowsIfNeededLocked(false) || toBeDisplayed) {
                     // Little hack here -- we -should- be able to rely on the
                     // function to return true if the IME has moved and needs
                     // its layer recomputed.  However, if the IME was hidden
@@ -2934,7 +2916,7 @@
             }
             configChanged = updateOrientationFromAppTokensLocked(false);
             performLayoutAndPlaceSurfacesLocked();
-            if (displayed && win.mIsWallpaper) {
+            if (toBeDisplayed && win.mIsWallpaper) {
                 updateWallpaperOffsetLocked(win, mAppDisplayWidth, mAppDisplayHeight, false);
             }
             if (win.mAppToken != null) {
@@ -2970,7 +2952,7 @@
         Binder.restoreCallingIdentity(origId);
 
         return (inTouchMode ? WindowManagerImpl.RELAYOUT_RES_IN_TOUCH_MODE : 0)
-                | (displayed ? WindowManagerImpl.RELAYOUT_RES_FIRST_TIME : 0)
+                | (toBeDisplayed ? WindowManagerImpl.RELAYOUT_RES_FIRST_TIME : 0)
                 | (surfaceChanged ? WindowManagerImpl.RELAYOUT_RES_SURFACE_CHANGED : 0)
                 | (animating ? WindowManagerImpl.RELAYOUT_RES_ANIMATING : 0);
     }
diff --git a/services/java/com/android/server/wm/WindowState.java b/services/java/com/android/server/wm/WindowState.java
index 1fd80c2..e2a904f 100644
--- a/services/java/com/android/server/wm/WindowState.java
+++ b/services/java/com/android/server/wm/WindowState.java
@@ -679,8 +679,7 @@
      */
     boolean isVisibleOrAdding() {
         final AppWindowToken atoken = mAppToken;
-        return ((mHasSurface && !mWinAnimator.mReportDestroySurface)
-                        || (!mRelayoutCalled && mViewVisibility == View.VISIBLE))
+        return (mHasSurface || (!mRelayoutCalled && mViewVisibility == View.VISIBLE))
                 && mPolicyVisibility && !mAttachedHidden
                 && (atoken == null || !atoken.hiddenRequested)
                 && !mExiting && !mDestroying;
diff --git a/services/java/com/android/server/wm/WindowStateAnimator.java b/services/java/com/android/server/wm/WindowStateAnimator.java
index 5516dea..355db6e 100644
--- a/services/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/java/com/android/server/wm/WindowStateAnimator.java
@@ -71,8 +71,6 @@
 
     Surface mSurface;
     Surface mPendingDestroySurface;
-    boolean mReportDestroySurface;
-    boolean mSurfacePendingDestroy;
 
     /**
      * Set when we have changed the size of the surface, to know that
@@ -561,8 +559,6 @@
 
     Surface createSurfaceLocked() {
         if (mSurface == null) {
-            mReportDestroySurface = false;
-            mSurfacePendingDestroy = false;
             if (DEBUG_ANIM || DEBUG_ORIENTATION) Slog.i(TAG,
                     "createSurface " + this + ": mDrawState=DRAW_PENDING");
             mDrawState = DRAW_PENDING;
@@ -694,7 +690,6 @@
             mWin.mAppToken.startingDisplayed = false;
         }
 
-        mDrawState = NO_SURFACE;
         if (mSurface != null) {
 
             int i = mWin.mChildWindows.size();
@@ -704,17 +699,6 @@
                 c.mAttachedHidden = true;
             }
 
-            if (mReportDestroySurface) {
-                mReportDestroySurface = false;
-                mSurfacePendingDestroy = true;
-                try {
-                    mWin.mClient.dispatchGetNewSurface();
-                    // We'll really destroy on the next time around.
-                    return;
-                } catch (RemoteException e) {
-                }
-            }
-
             try {
                 if (DEBUG_VISIBILITY) {
                     RuntimeException e = null;
@@ -760,6 +744,7 @@
             mSurfaceShown = false;
             mSurface = null;
             mWin.mHasSurface =false;
+            mDrawState = NO_SURFACE;
         }
     }
 
@@ -1147,7 +1132,7 @@
             }
         } else {
             if (DEBUG_ANIM) {
-                Slog.v(TAG, "prepareSurface: No changes in animation for " + mWin);
+                // Slog.v(TAG, "prepareSurface: No changes in animation for " + mWin);
             }
             displayed = true;
         }