Merge "Move flag for home launching from activity to task." into klp-dev
diff --git a/api/current.txt b/api/current.txt
index d31a38dc..739ef4c 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -25018,9 +25018,7 @@
     method public static void clearMetaKeyState(android.text.Editable, int);
     method public long clearMetaKeyState(long, int);
     method public static final int getMetaState(java.lang.CharSequence);
-    method public static final int getMetaState(java.lang.CharSequence, android.view.KeyEvent);
     method public static final int getMetaState(java.lang.CharSequence, int);
-    method public static final int getMetaState(java.lang.CharSequence, int, android.view.KeyEvent);
     method public static final int getMetaState(long);
     method public static final int getMetaState(long, int);
     method public static long handleKeyDown(long, int, android.view.KeyEvent);
@@ -30010,7 +30008,7 @@
     method public deprecated void onConsoleMessage(java.lang.String, int, java.lang.String);
     method public boolean onConsoleMessage(android.webkit.ConsoleMessage);
     method public boolean onCreateWindow(android.webkit.WebView, boolean, boolean, android.os.Message);
-    method public void onExceededDatabaseQuota(java.lang.String, java.lang.String, long, long, long, android.webkit.WebStorage.QuotaUpdater);
+    method public deprecated void onExceededDatabaseQuota(java.lang.String, java.lang.String, long, long, long, android.webkit.WebStorage.QuotaUpdater);
     method public void onGeolocationPermissionsHidePrompt();
     method public void onGeolocationPermissionsShowPrompt(java.lang.String, android.webkit.GeolocationPermissions.Callback);
     method public void onHideCustomView();
@@ -30020,7 +30018,7 @@
     method public boolean onJsPrompt(android.webkit.WebView, java.lang.String, java.lang.String, java.lang.String, android.webkit.JsPromptResult);
     method public deprecated boolean onJsTimeout();
     method public void onProgressChanged(android.webkit.WebView, int);
-    method public void onReachedMaxAppCacheSize(long, long, android.webkit.WebStorage.QuotaUpdater);
+    method public deprecated void onReachedMaxAppCacheSize(long, long, android.webkit.WebStorage.QuotaUpdater);
     method public void onReceivedIcon(android.webkit.WebView, android.graphics.Bitmap);
     method public void onReceivedTitle(android.webkit.WebView, java.lang.String);
     method public void onReceivedTouchIconUrl(android.webkit.WebView, java.lang.String, boolean);
@@ -30076,12 +30074,12 @@
     method public int getCacheMode();
     method public synchronized java.lang.String getCursiveFontFamily();
     method public synchronized boolean getDatabaseEnabled();
-    method public synchronized java.lang.String getDatabasePath();
+    method public deprecated synchronized java.lang.String getDatabasePath();
     method public synchronized int getDefaultFixedFontSize();
     method public synchronized int getDefaultFontSize();
     method public synchronized java.lang.String getDefaultTextEncodingName();
     method public static java.lang.String getDefaultUserAgent(android.content.Context);
-    method public android.webkit.WebSettings.ZoomDensity getDefaultZoom();
+    method public deprecated android.webkit.WebSettings.ZoomDensity getDefaultZoom();
     method public boolean getDisplayZoomControls();
     method public synchronized boolean getDomStorageEnabled();
     method public synchronized java.lang.String getFantasyFontFamily();
@@ -30118,11 +30116,11 @@
     method public void setCacheMode(int);
     method public synchronized void setCursiveFontFamily(java.lang.String);
     method public synchronized void setDatabaseEnabled(boolean);
-    method public synchronized void setDatabasePath(java.lang.String);
+    method public deprecated synchronized void setDatabasePath(java.lang.String);
     method public synchronized void setDefaultFixedFontSize(int);
     method public synchronized void setDefaultFontSize(int);
     method public synchronized void setDefaultTextEncodingName(java.lang.String);
-    method public void setDefaultZoom(android.webkit.WebSettings.ZoomDensity);
+    method public deprecated void setDefaultZoom(android.webkit.WebSettings.ZoomDensity);
     method public void setDisplayZoomControls(boolean);
     method public synchronized void setDomStorageEnabled(boolean);
     method public deprecated void setEnableSmoothTransition(boolean);
@@ -30165,9 +30163,10 @@
   public static final class WebSettings.LayoutAlgorithm extends java.lang.Enum {
     method public static android.webkit.WebSettings.LayoutAlgorithm valueOf(java.lang.String);
     method public static final android.webkit.WebSettings.LayoutAlgorithm[] values();
-    enum_constant public static final android.webkit.WebSettings.LayoutAlgorithm NARROW_COLUMNS;
+    enum_constant public static final deprecated android.webkit.WebSettings.LayoutAlgorithm NARROW_COLUMNS;
     enum_constant public static final android.webkit.WebSettings.LayoutAlgorithm NORMAL;
     enum_constant public static final deprecated android.webkit.WebSettings.LayoutAlgorithm SINGLE_COLUMN;
+    enum_constant public static final android.webkit.WebSettings.LayoutAlgorithm TEXT_AUTOSIZING;
   }
 
   public static final class WebSettings.PluginState extends java.lang.Enum {
@@ -30220,7 +30219,7 @@
     method public long getUsage();
   }
 
-  public static abstract interface WebStorage.QuotaUpdater {
+  public static abstract deprecated interface WebStorage.QuotaUpdater {
     method public abstract void updateQuota(long);
   }
 
@@ -30248,7 +30247,7 @@
     method public boolean canGoForward();
     method public deprecated boolean canZoomIn();
     method public deprecated boolean canZoomOut();
-    method public android.graphics.Picture capturePicture();
+    method public deprecated android.graphics.Picture capturePicture();
     method public void clearCache(boolean);
     method public void clearFormData();
     method public void clearHistory();
@@ -30265,7 +30264,7 @@
     method public void findAllAsync(java.lang.String);
     method public void findNext(boolean);
     method public void flingScroll(int, int);
-    method public void freeMemory();
+    method public deprecated void freeMemory();
     method public android.net.http.SslCertificate getCertificate();
     method public int getContentHeight();
     method public android.graphics.Bitmap getFavicon();
diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java
index f250029..5618cab 100644
--- a/core/java/android/content/ContentResolver.java
+++ b/core/java/android/content/ContentResolver.java
@@ -2316,8 +2316,7 @@
         }
 
         @Override
-        public void close() throws IOException {
-            super.close();
+        public void releaseResources() {
             if (!mProviderReleased) {
                 ContentResolver.this.releaseProvider(mContentProvider);
                 mProviderReleased = true;
diff --git a/core/java/android/nfc/cardemulation/ApduServiceInfo.java b/core/java/android/nfc/cardemulation/ApduServiceInfo.java
index 40a3612..d0feaa3 100644
--- a/core/java/android/nfc/cardemulation/ApduServiceInfo.java
+++ b/core/java/android/nfc/cardemulation/ApduServiceInfo.java
@@ -255,6 +255,10 @@
         return mRequiresDeviceUnlock;
     }
 
+    public String getDescription() {
+        return mDescription;
+    }
+
     public CharSequence loadLabel(PackageManager pm) {
         return mService.loadLabel(pm);
     }
@@ -287,6 +291,11 @@
             Log.e(TAG, "AID " + aid + " is not correctly formatted.");
             return false;
         }
+        // Minimum AID length is 5 bytes, 10 hex chars
+        if (aidLength < 10) {
+            Log.e(TAG, "AID " + aid + " is shorter than 5 bytes.");
+            return false;
+        }
         return true;
     }
 
diff --git a/core/java/android/os/ParcelFileDescriptor.java b/core/java/android/os/ParcelFileDescriptor.java
index 579971d..5a49b98 100644
--- a/core/java/android/os/ParcelFileDescriptor.java
+++ b/core/java/android/os/ParcelFileDescriptor.java
@@ -564,7 +564,11 @@
     @Override
     public void close() throws IOException {
         if (mWrapped != null) {
-            mWrapped.close();
+            try {
+                mWrapped.close();
+            } finally {
+                releaseResources();
+            }
         } else {
             closeWithStatus(Status.OK, null);
         }
@@ -579,7 +583,11 @@
      */
     public void closeWithError(String msg) throws IOException {
         if (mWrapped != null) {
-            mWrapped.closeWithError(msg);
+            try {
+                mWrapped.closeWithError(msg);
+            } finally {
+                releaseResources();
+            }
         } else {
             if (msg == null) {
                 throw new IllegalArgumentException("Message must not be null");
@@ -588,17 +596,22 @@
         }
     }
 
-    private void closeWithStatus(int status, String msg) throws IOException {
-        if (mWrapped != null) {
-            mWrapped.closeWithStatus(status, msg);
-        } else {
-            if (mClosed) return;
-            mClosed = true;
-            mGuard.close();
-            // Status MUST be sent before closing actual descriptor
-            writeCommStatusAndClose(status, msg);
-            IoUtils.closeQuietly(mFd);
-        }
+    private void closeWithStatus(int status, String msg) {
+        if (mClosed) return;
+        mClosed = true;
+        mGuard.close();
+        // Status MUST be sent before closing actual descriptor
+        writeCommStatusAndClose(status, msg);
+        IoUtils.closeQuietly(mFd);
+        releaseResources();
+    }
+
+    /**
+     * Called when the fd is being closed, for subclasses to release any other resources
+     * associated with it, such as acquired providers.
+     * @hide
+     */
+    public void releaseResources() {
     }
 
     private byte[] getOrCreateStatusBuffer() {
@@ -793,6 +806,9 @@
 
     @Override
     protected void finalize() throws Throwable {
+        if (mWrapped != null) {
+            releaseResources();
+        }
         if (mGuard != null) {
             mGuard.warnIfOpen();
         }
@@ -822,7 +838,11 @@
     @Override
     public void writeToParcel(Parcel out, int flags) {
         if (mWrapped != null) {
-            mWrapped.writeToParcel(out, flags);
+            try {
+                mWrapped.writeToParcel(out, flags);
+            } finally {
+                releaseResources();
+            }
         } else {
             out.writeFileDescriptor(mFd);
             if (mCommFd != null) {
@@ -832,11 +852,8 @@
                 out.writeInt(0);
             }
             if ((flags & PARCELABLE_WRITE_RETURN_VALUE) != 0 && !mClosed) {
-                try {
-                    // Not a real close, so emit no status
-                    closeWithStatus(Status.SILENCE, null);
-                } catch (IOException e) {
-                }
+                // Not a real close, so emit no status
+                closeWithStatus(Status.SILENCE, null);
             }
         }
     }
diff --git a/core/java/android/text/method/ArrowKeyMovementMethod.java b/core/java/android/text/method/ArrowKeyMovementMethod.java
index ba6f1d4..30bb447 100644
--- a/core/java/android/text/method/ArrowKeyMovementMethod.java
+++ b/core/java/android/text/method/ArrowKeyMovementMethod.java
@@ -56,7 +56,7 @@
                     if (event.getAction() == KeyEvent.ACTION_DOWN
                             && event.getRepeatCount() == 0
                             && MetaKeyKeyListener.getMetaState(buffer,
-                                        MetaKeyKeyListener.META_SELECTING, event) != 0) {
+                                        MetaKeyKeyListener.META_SELECTING) != 0) {
                         return widget.showContextMenu();
                     }
                 }
diff --git a/core/java/android/text/method/BaseKeyListener.java b/core/java/android/text/method/BaseKeyListener.java
index 63607fa..4fede32 100644
--- a/core/java/android/text/method/BaseKeyListener.java
+++ b/core/java/android/text/method/BaseKeyListener.java
@@ -75,7 +75,7 @@
         }
 
         // Alt+Backspace or Alt+ForwardDelete deletes the current line, if possible.
-        if (getMetaState(content, META_ALT_ON, event) == 1) {
+        if (event.isAltPressed() || getMetaState(content, META_ALT_ON) == 1) {
             if (deleteLine(view, content)) {
                 return true;
             }
diff --git a/core/java/android/text/method/BaseMovementMethod.java b/core/java/android/text/method/BaseMovementMethod.java
index 155a2c4..113a4be 100644
--- a/core/java/android/text/method/BaseMovementMethod.java
+++ b/core/java/android/text/method/BaseMovementMethod.java
@@ -135,7 +135,7 @@
      */
     protected int getMovementMetaState(Spannable buffer, KeyEvent event) {
         // We ignore locked modifiers and SHIFT.
-        int metaState = MetaKeyKeyListener.getMetaState(buffer, event)
+        int metaState = (event.getMetaState() | MetaKeyKeyListener.getMetaState(buffer))
                 & ~(MetaKeyKeyListener.META_ALT_LOCKED | MetaKeyKeyListener.META_SYM_LOCKED);
         return KeyEvent.normalizeMetaState(metaState) & ~KeyEvent.META_SHIFT_MASK;
     }
diff --git a/core/java/android/text/method/DialerKeyListener.java b/core/java/android/text/method/DialerKeyListener.java
index bb8b0de..ce51fae 100644
--- a/core/java/android/text/method/DialerKeyListener.java
+++ b/core/java/android/text/method/DialerKeyListener.java
@@ -53,7 +53,7 @@
      * from the KeyEvent.
      */
     protected int lookup(KeyEvent event, Spannable content) {
-        int meta = getMetaState(content, event);
+        int meta = event.getMetaState() | getMetaState(content);
         int number = event.getNumber();
 
         /*
diff --git a/core/java/android/text/method/MetaKeyKeyListener.java b/core/java/android/text/method/MetaKeyKeyListener.java
index e9db5fd..5ebb957 100644
--- a/core/java/android/text/method/MetaKeyKeyListener.java
+++ b/core/java/android/text/method/MetaKeyKeyListener.java
@@ -163,29 +163,6 @@
                getActive(text, SELECTING, META_SELECTING, META_SELECTING);
     }
 
-    /**
-     * Gets the state of the meta keys for a specific key event.
-     *
-     * For input devices that use toggled key modifiers, the `toggled' state
-     * is stored into the text buffer. This method retrieves the meta state
-     * for this event, accounting for the stored state. If the event has been
-     * created by a device that does not support toggled key modifiers, like
-     * a virtual device for example, the stored state is ignored.
-     *
-     * @param text the buffer in which the meta key would have been pressed.
-     * @param event the event for which to evaluate the meta state.
-     * @return an integer in which each bit set to one represents a pressed
-     *         or locked meta key.
-     */
-    public static final int getMetaState(final CharSequence text, final KeyEvent event) {
-        int metaState = event.getMetaState();
-        if (event.getKeyCharacterMap().getModifierBehavior()
-                == KeyCharacterMap.MODIFIER_BEHAVIOR_CHORDED_OR_TOGGLED) {
-            metaState |= getMetaState(text);
-        }
-        return metaState;
-    }
-
     // As META_SELECTING is @hide we should not mention it in public comments, hence the
     // omission in @param meta
     /**
@@ -215,37 +192,6 @@
         }
     }
 
-    /**
-     * Gets the state of a particular meta key to use with a particular key event.
-     *
-     * If the key event has been created by a device that does not support toggled
-     * key modifiers, like a virtual keyboard for example, only the meta state in
-     * the key event is considered.
-     *
-     * @param meta META_SHIFT_ON, META_ALT_ON, META_SYM_ON
-     * @param text the buffer in which the meta key would have been pressed.
-     * @param event the event for which to evaluate the meta state.
-     * @return 0 if inactive, 1 if active, 2 if locked.
-     */
-    public static final int getMetaState(final CharSequence text, final int meta,
-            final KeyEvent event) {
-        int metaState = event.getMetaState();
-        if (event.getKeyCharacterMap().getModifierBehavior()
-                == KeyCharacterMap.MODIFIER_BEHAVIOR_CHORDED_OR_TOGGLED) {
-            metaState |= getMetaState(text);
-        }
-        if (META_SELECTING == meta) {
-            // #getMetaState(long, int) does not support META_SELECTING, but we want the same
-            // behavior as #getMetaState(CharSequence, int) so we need to do it here
-            if ((metaState & META_SELECTING) != 0) {
-                // META_SELECTING is only ever set to PRESSED and can't be LOCKED, so return 1
-                return 1;
-            }
-            return 0;
-        }
-        return getMetaState(metaState, meta);
-    }
-
     private static int getActive(CharSequence text, Object meta,
                                  int on, int lock) {
         if (!(text instanceof Spanned)) {
diff --git a/core/java/android/text/method/NumberKeyListener.java b/core/java/android/text/method/NumberKeyListener.java
index 988d566..5d4c732 100644
--- a/core/java/android/text/method/NumberKeyListener.java
+++ b/core/java/android/text/method/NumberKeyListener.java
@@ -41,7 +41,7 @@
     protected abstract char[] getAcceptedChars();
 
     protected int lookup(KeyEvent event, Spannable content) {
-        return event.getMatch(getAcceptedChars(), getMetaState(content, event));
+        return event.getMatch(getAcceptedChars(), event.getMetaState() | getMetaState(content));
     }
 
     public CharSequence filter(CharSequence source, int start, int end,
diff --git a/core/java/android/text/method/QwertyKeyListener.java b/core/java/android/text/method/QwertyKeyListener.java
index 0bd46bc..98316ae 100644
--- a/core/java/android/text/method/QwertyKeyListener.java
+++ b/core/java/android/text/method/QwertyKeyListener.java
@@ -108,7 +108,7 @@
 
         // QWERTY keyboard normal case
 
-        int i = event.getUnicodeChar(getMetaState(content, event));
+        int i = event.getUnicodeChar(event.getMetaState() | getMetaState(content));
 
         if (!mFullKeyboard) {
             int count = event.getRepeatCount();
diff --git a/core/java/android/transition/Fade.java b/core/java/android/transition/Fade.java
index 4cc2c42..5f948bd 100644
--- a/core/java/android/transition/Fade.java
+++ b/core/java/android/transition/Fade.java
@@ -41,7 +41,6 @@
     private static boolean DBG = Transition.DBG && false;
 
     private static final String LOG_TAG = "Fade";
-    private static final String PROPNAME_ALPHA = "android:fade:alpha";
     private static final String PROPNAME_SCREEN_X = "android:fade:screenX";
     private static final String PROPNAME_SCREEN_Y = "android:fade:screenY";
 
@@ -90,7 +89,8 @@
             }
             return null;
         }
-        final ObjectAnimator anim = ObjectAnimator.ofFloat(view, "alpha", startAlpha, endAlpha);
+        final ObjectAnimator anim = ObjectAnimator.ofFloat(view, "transitionAlpha", startAlpha,
+                endAlpha);
         if (DBG) {
             Log.d(LOG_TAG, "Created animator " + anim);
         }
@@ -102,8 +102,6 @@
     }
 
     private void captureValues(TransitionValues transitionValues) {
-        float alpha = transitionValues.view.getAlpha();
-        transitionValues.values.put(PROPNAME_ALPHA, alpha);
         int[] loc = new int[2];
         transitionValues.view.getLocationOnScreen(loc);
         transitionValues.values.put(PROPNAME_SCREEN_X, loc[0]);
@@ -116,29 +114,6 @@
         captureValues(transitionValues);
     }
 
-
-    @Override
-    public void captureEndValues(TransitionValues transitionValues) {
-        super.captureEndValues(transitionValues);
-    }
-
-    @Override
-    public Animator createAnimator(ViewGroup sceneRoot, TransitionValues startValues,
-            TransitionValues endValues) {
-        Animator animator = super.createAnimator(sceneRoot, startValues, endValues);
-        if (animator == null && startValues != null && endValues != null) {
-            boolean endVisible = isVisible(endValues);
-            final View endView = endValues.view;
-            float endAlpha = endView.getAlpha();
-            float startAlpha = (Float) startValues.values.get(PROPNAME_ALPHA);
-            if ((endVisible && startAlpha < endAlpha && (mFadingMode & Fade.IN) != 0) ||
-                    (!endVisible && startAlpha > endAlpha && (mFadingMode & Fade.OUT) != 0)) {
-                animator = createAnimation(endView, startAlpha, endAlpha, null);
-            }
-        }
-        return animator;
-    }
-
     @Override
     public Animator onAppear(ViewGroup sceneRoot,
             TransitionValues startValues, int startVisibility,
@@ -152,40 +127,37 @@
             Log.d(LOG_TAG, "Fade.onAppear: startView, startVis, endView, endVis = " +
                     startView + ", " + startVisibility + ", " + endView + ", " + endVisibility);
         }
-        // if alpha < 1, just fade it in from the current value
-        if (endView.getAlpha() == 1.0f) {
-            endView.setAlpha(0);
-            TransitionListener transitionListener = new TransitionListenerAdapter() {
-                boolean mCanceled = false;
-                float mPausedAlpha;
+        endView.setTransitionAlpha(0);
+        TransitionListener transitionListener = new TransitionListenerAdapter() {
+            boolean mCanceled = false;
+            float mPausedAlpha;
 
-                @Override
-                public void onTransitionCancel(Transition transition) {
-                    endView.setAlpha(1);
-                    mCanceled = true;
-                }
+            @Override
+            public void onTransitionCancel(Transition transition) {
+                endView.setTransitionAlpha(1);
+                mCanceled = true;
+            }
 
-                @Override
-                public void onTransitionEnd(Transition transition) {
-                    if (!mCanceled) {
-                        endView.setAlpha(1);
-                    }
+            @Override
+            public void onTransitionEnd(Transition transition) {
+                if (!mCanceled) {
+                    endView.setTransitionAlpha(1);
                 }
+            }
 
-                @Override
-                public void onTransitionPause(Transition transition) {
-                    mPausedAlpha = endView.getAlpha();
-                    endView.setAlpha(1);
-                }
+            @Override
+            public void onTransitionPause(Transition transition) {
+                mPausedAlpha = endView.getTransitionAlpha();
+                endView.setTransitionAlpha(1);
+            }
 
-                @Override
-                public void onTransitionResume(Transition transition) {
-                    endView.setAlpha(mPausedAlpha);
-                }
-            };
-            addListener(transitionListener);
-        }
-        return createAnimation(endView, endView.getAlpha(), 1, null);
+            @Override
+            public void onTransitionResume(Transition transition) {
+                endView.setTransitionAlpha(mPausedAlpha);
+            }
+        };
+        addListener(transitionListener);
+        return createAnimation(endView, 0, 1, null);
     }
 
     @Override
@@ -236,7 +208,7 @@
             overlayView.offsetTopAndBottom((screenY - loc[1]) - overlayView.getTop());
             sceneRoot.getOverlay().add(overlayView);
             // TODO: add automatic facility to Visibility superclass for keeping views around
-            final float startAlpha = view.getAlpha();
+            final float startAlpha = 1;
             float endAlpha = 0;
             final View finalView = view;
             final View finalOverlayView = overlayView;
@@ -245,7 +217,7 @@
             final AnimatorListenerAdapter endListener = new AnimatorListenerAdapter() {
                 @Override
                 public void onAnimationEnd(Animator animation) {
-                    finalView.setAlpha(startAlpha);
+                    finalView.setTransitionAlpha(startAlpha);
                     // TODO: restore view offset from overlay repositioning
                     if (finalViewToKeep != null) {
                         finalViewToKeep.setVisibility(finalVisibility);
@@ -276,7 +248,7 @@
             // VISIBLE for the duration of the transition
             viewToKeep.setVisibility((View.VISIBLE));
             // TODO: add automatic facility to Visibility superclass for keeping views around
-            final float startAlpha = view.getAlpha();
+            final float startAlpha = 1;
             float endAlpha = 0;
             final View finalView = view;
             final View finalOverlayView = overlayView;
@@ -291,8 +263,8 @@
                     if (finalViewToKeep != null && !mCanceled) {
                         finalViewToKeep.setVisibility(finalVisibility);
                     }
-                    mPausedAlpha = finalView.getAlpha();
-                    finalView.setAlpha(startAlpha);
+                    mPausedAlpha = finalView.getTransitionAlpha();
+                    finalView.setTransitionAlpha(startAlpha);
                 }
 
                 @Override
@@ -300,21 +272,21 @@
                     if (finalViewToKeep != null && !mCanceled) {
                         finalViewToKeep.setVisibility(View.VISIBLE);
                     }
-                    finalView.setAlpha(mPausedAlpha);
+                    finalView.setTransitionAlpha(mPausedAlpha);
                 }
 
                 @Override
                 public void onAnimationCancel(Animator animation) {
                     mCanceled = true;
                     if (mPausedAlpha >= 0) {
-                        finalView.setAlpha(mPausedAlpha);
+                        finalView.setTransitionAlpha(mPausedAlpha);
                     }
                 }
 
                 @Override
                 public void onAnimationEnd(Animator animation) {
                     if (!mCanceled) {
-                        finalView.setAlpha(startAlpha);
+                        finalView.setTransitionAlpha(startAlpha);
                     }
                     // TODO: restore view offset from overlay repositioning
                     if (finalViewToKeep != null && !mCanceled) {
diff --git a/core/java/android/transition/Transition.java b/core/java/android/transition/Transition.java
index 60b4708..4a99153 100644
--- a/core/java/android/transition/Transition.java
+++ b/core/java/android/transition/Transition.java
@@ -353,7 +353,7 @@
                 if (endValues.viewValues.get(view) != null) {
                     end = endValues.viewValues.get(view);
                     endCopy.remove(view);
-                } else {
+                } else if (id != View.NO_ID) {
                     end = endValues.idValues.get(id);
                     View removeView = null;
                     for (View viewToRemove : endCopy.keySet()) {
diff --git a/core/java/android/transition/TransitionSet.java b/core/java/android/transition/TransitionSet.java
index f72b36e..6fdd309 100644
--- a/core/java/android/transition/TransitionSet.java
+++ b/core/java/android/transition/TransitionSet.java
@@ -354,7 +354,7 @@
         clone.mTransitions = new ArrayList<Transition>();
         int numTransitions = mTransitions.size();
         for (int i = 0; i < numTransitions; ++i) {
-            clone.mTransitions.add((Transition) mTransitions.get(i).clone());
+            clone.addTransition((Transition) mTransitions.get(i).clone());
         }
         return clone;
     }
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index a5db6ee..4680e76 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -2894,6 +2894,13 @@
          */
         @ViewDebug.ExportedProperty
         float mAlpha = 1f;
+
+        /**
+         * The opacity of the view as manipulated by the Fade transition. This is a hidden
+         * property only used by transitions, which is composited with the other alpha
+         * values to calculate the final visual alpha value.
+         */
+        float mTransitionAlpha = 1f;
     }
 
     TransformationInfo mTransformationInfo;
@@ -5335,7 +5342,8 @@
                 View view = (View) current;
                 // We have attach info so this view is attached and there is no
                 // need to check whether we reach to ViewRootImpl on the way up.
-                if (view.getAlpha() <= 0 || view.getVisibility() != VISIBLE) {
+                if (view.getAlpha() <= 0 || view.getTransitionAlpha() <= 0 ||
+                        view.getVisibility() != VISIBLE) {
                     return false;
                 }
                 current = view.mParent;
@@ -9786,7 +9794,7 @@
                 mPrivateFlags &= ~PFLAG_ALPHA_SET;
                 invalidateViewProperty(true, false);
                 if (mDisplayList != null) {
-                    mDisplayList.setAlpha(alpha);
+                    mDisplayList.setAlpha(getFinalAlpha());
                 }
             }
         }
@@ -9813,7 +9821,7 @@
             } else {
                 mPrivateFlags &= ~PFLAG_ALPHA_SET;
                 if (mDisplayList != null) {
-                    mDisplayList.setAlpha(alpha);
+                    mDisplayList.setAlpha(getFinalAlpha());
                 }
             }
         }
@@ -9821,6 +9829,51 @@
     }
 
     /**
+     * This property is hidden and intended only for use by the Fade transition, which
+     * animates it to produce a visual translucency that does not side-effect (or get
+     * affected by) the real alpha property. This value is composited with the other
+     * alpha value (and the AlphaAnimation value, when that is present) to produce
+     * a final visual translucency result, which is what is passed into the DisplayList.
+     *
+     * @hide
+     */
+    public void setTransitionAlpha(float alpha) {
+        ensureTransformationInfo();
+        if (mTransformationInfo.mTransitionAlpha != alpha) {
+            mTransformationInfo.mTransitionAlpha = alpha;
+            mPrivateFlags &= ~PFLAG_ALPHA_SET;
+            invalidateViewProperty(true, false);
+            if (mDisplayList != null) {
+                mDisplayList.setAlpha(getFinalAlpha());
+            }
+        }
+    }
+
+    /**
+     * Calculates the visual alpha of this view, which is a combination of the actual
+     * alpha value and the transitionAlpha value (if set).
+     */
+    private float getFinalAlpha() {
+        if (mTransformationInfo != null) {
+            return mTransformationInfo.mAlpha * mTransformationInfo.mTransitionAlpha;
+        }
+        return 1;
+    }
+
+    /**
+     * This property is hidden and intended only for use by the Fade transition, which
+     * animates it to produce a visual translucency that does not side-effect (or get
+     * affected by) the real alpha property. This value is composited with the other
+     * alpha value (and the AlphaAnimation value, when that is present) to produce
+     * a final visual translucency result, which is what is passed into the DisplayList.
+     *
+     * @hide
+     */
+    public float getTransitionAlpha() {
+        return mTransformationInfo != null ? mTransformationInfo.mTransitionAlpha : 1;
+    }
+
+    /**
      * Top position of this view relative to its parent.
      *
      * @return The top of this view, in pixels.
@@ -10913,7 +10966,7 @@
     @ViewDebug.ExportedProperty(category = "drawing")
     public boolean isOpaque() {
         return (mPrivateFlags & PFLAG_OPAQUE_MASK) == PFLAG_OPAQUE_MASK &&
-                ((mTransformationInfo != null ? mTransformationInfo.mAlpha : 1.0f) >= 1.0f);
+                getFinalAlpha() >= 1.0f;
     }
 
     /**
@@ -13868,7 +13921,7 @@
                 }
             }
             if (mTransformationInfo != null) {
-                alpha *= mTransformationInfo.mAlpha;
+                alpha *= getFinalAlpha();
                 if (alpha < 1) {
                     final int multipliedAlpha = (int) (255 * alpha);
                     if (onSetAlpha(multipliedAlpha)) {
@@ -14057,8 +14110,8 @@
             }
         }
 
-        float alpha = useDisplayListProperties ? 1 : getAlpha();
-        if (transformToApply != null || alpha < 1 || !hasIdentityMatrix() ||
+        float alpha = useDisplayListProperties ? 1 : (getAlpha() * getTransitionAlpha());
+        if (transformToApply != null || alpha < 1 ||  !hasIdentityMatrix() ||
                 (mPrivateFlags3 & PFLAG3_VIEW_IS_ANIMATING_ALPHA) == PFLAG3_VIEW_IS_ANIMATING_ALPHA) {
             if (transformToApply != null || !childHasIdentityMatrix) {
                 int transX = 0;
@@ -14115,7 +14168,7 @@
                             layerFlags |= Canvas.CLIP_TO_LAYER_SAVE_FLAG;
                         }
                         if (useDisplayListProperties) {
-                            displayList.setAlpha(alpha * getAlpha());
+                            displayList.setAlpha(alpha * getAlpha() * getTransitionAlpha());
                         } else  if (layerType == LAYER_TYPE_NONE) {
                             final int scrollX = hasDisplayList ? 0 : sx;
                             final int scrollY = hasDisplayList ? 0 : sy;
diff --git a/core/java/android/view/ViewTreeObserver.java b/core/java/android/view/ViewTreeObserver.java
index ad8b51d..f9298ea 100644
--- a/core/java/android/view/ViewTreeObserver.java
+++ b/core/java/android/view/ViewTreeObserver.java
@@ -990,10 +990,10 @@
             mStart = false;
             if (mDataCopy != null) {
                 mData = mDataCopy;
+                mAccess.mData.clear();
+                mAccess.mSize = 0;
             }
             mDataCopy = null;
-            mAccess.mData.clear();
-            mAccess.mSize = 0;
         }
 
         int size() {
diff --git a/core/java/android/webkit/WebChromeClient.java b/core/java/android/webkit/WebChromeClient.java
index 21b0578..aa57423 100644
--- a/core/java/android/webkit/WebChromeClient.java
+++ b/core/java/android/webkit/WebChromeClient.java
@@ -238,9 +238,10 @@
     * @param totalQuota The total quota for all origins, in bytes
     * @param quotaUpdater An instance of {@link WebStorage.QuotaUpdater} which
     *                     must be used to inform the WebView of the new quota.
+    * @deprecated This method is no longer called; WebView now uses the HTML5 / JavaScript Quota
+    *             Management API.
     */
-    // Note that the callback must always be executed at some point to ensure
-    // that the sleeping WebCore thread is woken up.
+    @Deprecated
     public void onExceededDatabaseQuota(String url, String databaseIdentifier,
             long quota, long estimatedDatabaseSize, long totalQuota,
             WebStorage.QuotaUpdater quotaUpdater) {
@@ -263,9 +264,10 @@
     * @param quota the current maximum Application Cache size, in bytes
     * @param quotaUpdater An instance of {@link WebStorage.QuotaUpdater} which
     *                     must be used to inform the WebView of the new quota.
+    * @deprecated This method is no longer called; WebView now uses the HTML5 / JavaScript Quota
+    *             Management API.
     */
-    // Note that the callback must always be executed at some point to ensure
-    // that the sleeping WebCore thread is woken up.
+    @Deprecated
     public void onReachedMaxAppCacheSize(long requiredStorage, long quota,
             WebStorage.QuotaUpdater quotaUpdater) {
         quotaUpdater.updateQuota(quota);
diff --git a/core/java/android/webkit/WebSettings.java b/core/java/android/webkit/WebSettings.java
index 7a38a16..98ef66e 100644
--- a/core/java/android/webkit/WebSettings.java
+++ b/core/java/android/webkit/WebSettings.java
@@ -33,14 +33,17 @@
     /**
      * Enum for controlling the layout of html.
      * <ul>
-     *   <li>NORMAL means no rendering changes.</li>
+     *   <li>NORMAL means no rendering changes. This is the recommended choice for maximum
+     *       compatibility across different platforms and Android versions.</li>
      *   <li>SINGLE_COLUMN moves all content into one column that is the width of the
      *       view.</li>
-     *   <li>NARROW_COLUMNS makes all columns no wider than the screen if possible.</li>
+     *   <li>NARROW_COLUMNS makes all columns no wider than the screen if possible. Only use
+     *       this for API levels prior to {@link android.os.Build.VERSION_CODES#KITKAT}.</li>
      *   <li>TEXT_AUTOSIZING boosts font size of paragraphs based on heuristics to make
      *       the text readable when viewing a wide-viewport layout in the overview mode.
      *       It is recommended to enable zoom support {@link #setSupportZoom} when
-     *       using this mode.</li>
+     *       using this mode. Supported from API level
+     *       {@link android.os.Build.VERSION_CODES#KITKAT}</li>
      * </ul>
      */
     // XXX: These must match LayoutAlgorithm in Settings.h in WebCore.
@@ -51,10 +54,11 @@
          */
         @Deprecated
         SINGLE_COLUMN,
-        NARROW_COLUMNS,
         /**
-         * @hide
+         * @deprecated This algorithm is now obsolete.
          */
+        @Deprecated
+        NARROW_COLUMNS,
         TEXT_AUTOSIZING
     }
 
@@ -510,7 +514,10 @@
      * and {@link #setUseWideViewPort} can be used.
      *
      * @param zoom the zoom density
+     * @deprecated This method is no longer supported, see the function documentation for
+     *             recommended alternatives.
      */
+    @Deprecated
     public void setDefaultZoom(ZoomDensity zoom) {
         throw new MustOverrideException();
     }
@@ -523,6 +530,7 @@
      *
      * @return the zoom density
      * @see #setDefaultZoom
+     * @deprecated Will only return the default value.
      */
     public ZoomDensity getDefaultZoom() {
         throw new MustOverrideException();
@@ -1059,10 +1067,13 @@
      *
      * @param databasePath a path to the directory where databases should be
      *                     saved.
+     * @deprecated Database paths are managed by the implementation and calling this method
+     *             will have no effect.
      */
     // This will update WebCore when the Sync runs in the C++ side.
     // Note that the WebCore Database Tracker only allows the path to be set
     // once.
+    @Deprecated
     public synchronized void setDatabasePath(String databasePath) {
         throw new MustOverrideException();
     }
@@ -1161,7 +1172,9 @@
      *
      * @return the String path to the database storage API databases
      * @see #setDatabasePath
+     * @deprecated Database paths are managed by the implementation this method is obsolete.
      */
+    @Deprecated
     public synchronized String getDatabasePath() {
         throw new MustOverrideException();
     }
diff --git a/core/java/android/webkit/WebStorage.java b/core/java/android/webkit/WebStorage.java
index 7d9373c..3bfe9cf 100644
--- a/core/java/android/webkit/WebStorage.java
+++ b/core/java/android/webkit/WebStorage.java
@@ -41,12 +41,9 @@
      * See
      * {@link WebChromeClient#onExceededDatabaseQuota} and
      * {@link WebChromeClient#onReachedMaxAppCacheSize}.
+     * @deprecated This class is obsolete and no longer used.
      */
-    // We primarily want this to allow us to call back the sleeping WebCore
-    // thread from outside the WebViewCore class (as the native call is
-    // private). It is imperative that the setDatabaseQuota method is
-    // executed after a decision to either allow or deny new quota is made,
-    // otherwise the WebCore thread will remain asleep.
+    @Deprecated
     public interface QuotaUpdater {
         /**
          * Provides a new quota, specified in bytes.
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 15331dc..d05bba7 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -1058,9 +1058,20 @@
      * {@link android.os.Build.VERSION_CODES#HONEYCOMB} and
      * {@link android.os.Build.VERSION_CODES#ICE_CREAM_SANDWICH} inclusive, the
      * picture does not include fixed position elements or scrollable divs.
+     * <p>
+     * Note that from {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR1} the returned picture
+     * should only be drawn into bitmap-backed Canvas - using any other type of Canvas will involve
+     * additional conversion at a cost in memory and performance. Also the
+     * {@link android.graphics.Picture#createFromStream} and
+     * {@link android.graphics.Picture#writeToStream} methods are not supported on the
+     * returned object.
+     *
+     * @deprecated Use {@link #onDraw} to obtain a bitmap snapshot of the WebView, or
+     * {@link #saveWebArchive} or {@link #exportToPdf} to save the content to a file.
      *
      * @return a picture that captures the current contents of this WebView
      */
+    @Deprecated
     public Picture capturePicture() {
         checkThread();
         if (DebugFlags.TRACE_API) Log.d(LOGTAG, "capturePicture");
@@ -1342,7 +1353,10 @@
     /**
      * Informs this WebView that memory is low so that it can free any available
      * memory.
+     * @deprecated Memory caches are automatically dropped when no longer needed, and in response
+     *             to system memory pressure.
      */
+    @Deprecated
     public void freeMemory() {
         checkThread();
         if (DebugFlags.TRACE_API) Log.d(LOGTAG, "freeMemory");
diff --git a/core/jni/android/graphics/BitmapFactory.cpp b/core/jni/android/graphics/BitmapFactory.cpp
index f9bb233..9c20de2 100644
--- a/core/jni/android/graphics/BitmapFactory.cpp
+++ b/core/jni/android/graphics/BitmapFactory.cpp
@@ -3,6 +3,7 @@
 #include "BitmapFactory.h"
 #include "NinePatchPeeker.h"
 #include "SkData.h"
+#include "SkFrontBufferedStream.h"
 #include "SkImageDecoder.h"
 #include "SkImageRef_ashmem.h"
 #include "SkImageRef_GlobalPool.h"
@@ -120,7 +121,7 @@
     }
 }
 
-static SkPixelRef* installPixelRef(SkBitmap* bitmap, SkStream* stream,
+static SkPixelRef* installPixelRef(SkBitmap* bitmap, SkStreamRewindable* stream,
         int sampleSize, bool ditherImage) {
 
     SkImageRef* pr;
@@ -465,13 +466,17 @@
         jobject padding, jobject options) {
 
     jobject bitmap = NULL;
-    SkAutoTUnref<SkStreamRewindable> stream(GetRewindableStream(env, is, storage));
+    SkAutoTUnref<SkStream> stream(CreateJavaInputStreamAdaptor(env, is, storage));
 
     if (stream.get()) {
+        // Need to buffer enough input to be able to rewind as much as might be read by a decoder
+        // trying to determine the stream's format. Currently the most is 64, read by
+        // SkImageDecoder_libwebp.
+        // FIXME: Get this number from SkImageDecoder
+        SkAutoTUnref<SkStreamRewindable> bufferedStream(SkFrontBufferedStream::Create(stream, 64));
+        SkASSERT(bufferedStream.get() != NULL);
         // for now we don't allow purgeable with java inputstreams
-        // FIXME: GetRewindableStream may have made a copy, in which case
-        // purgeable should be allowed.
-        bitmap = doDecode(env, stream, padding, options, false, false);
+        bitmap = doDecode(env, bufferedStream, padding, options, false, false);
     }
     return bitmap;
 }
diff --git a/core/jni/android/graphics/CreateJavaOutputStreamAdaptor.cpp b/core/jni/android/graphics/CreateJavaOutputStreamAdaptor.cpp
index f773f59..da8f083 100644
--- a/core/jni/android/graphics/CreateJavaOutputStreamAdaptor.cpp
+++ b/core/jni/android/graphics/CreateJavaOutputStreamAdaptor.cpp
@@ -5,18 +5,12 @@
 #include "SkStream.h"
 #include "SkTypes.h"
 #include "Utils.h"
-#include <androidfw/Asset.h>
 
-static jmethodID    gInputStream_resetMethodID;
-static jmethodID    gInputStream_markMethodID;
-static jmethodID    gInputStream_markSupportedMethodID;
 static jmethodID    gInputStream_readMethodID;
 static jmethodID    gInputStream_skipMethodID;
 
-class RewindableJavaStream;
-
 /**
- *  Non-rewindable wrapper for a Java InputStream.
+ *  Wrapper for a Java InputStream.
  */
 class JavaInputStreamAdaptor : public SkStream {
 public:
@@ -64,25 +58,6 @@
     }
 
 private:
-    // Does not override rewind, since a JavaInputStreamAdaptor's interface
-    // does not support rewinding. RewindableJavaStream, which is a friend,
-    // will be able to call this method to rewind.
-    bool doRewind() {
-        JNIEnv* env = fEnv;
-
-        fBytesRead = 0;
-        fIsAtEnd = false;
-
-        env->CallVoidMethod(fJavaInputStream, gInputStream_resetMethodID);
-        if (env->ExceptionCheck()) {
-            env->ExceptionDescribe();
-            env->ExceptionClear();
-            SkDebugf("------- reset threw an exception\n");
-            return false;
-        }
-        return true;
-    }
-
     size_t doRead(void* buffer, size_t size) {
         JNIEnv* env = fEnv;
         size_t bytesRead = 0;
@@ -148,9 +123,6 @@
     size_t      fCapacity;
     size_t      fBytesRead;
     bool        fIsAtEnd;
-
-    // Allows access to doRewind and fBytesRead.
-    friend class RewindableJavaStream;
 };
 
 SkStream* CreateJavaInputStreamAdaptor(JNIEnv* env, jobject stream,
@@ -190,123 +162,6 @@
     return adaptor_to_mem_stream(adaptor.get());
 }
 
-/**
- *  Wrapper for a Java InputStream which is rewindable and
- *  has a length.
- */
-class RewindableJavaStream : public SkStreamRewindable {
-public:
-    // RewindableJavaStream takes ownership of adaptor.
-    RewindableJavaStream(JavaInputStreamAdaptor* adaptor, size_t length)
-        : fAdaptor(adaptor)
-        , fLength(length) {
-        SkASSERT(fAdaptor != NULL);
-    }
-
-    virtual ~RewindableJavaStream() {
-        fAdaptor->unref();
-    }
-
-    virtual bool rewind() {
-        return fAdaptor->doRewind();
-    }
-
-    virtual size_t read(void* buffer, size_t size) {
-        return fAdaptor->read(buffer, size);
-    }
-
-    virtual bool isAtEnd() const {
-        return fAdaptor->isAtEnd();
-    }
-
-    virtual size_t getLength() const {
-        return fLength;
-    }
-
-    virtual bool hasLength() const {
-        return true;
-    }
-
-    virtual SkStreamRewindable* duplicate() const {
-        // Duplicating this stream requires rewinding and
-        // reading, which modify this Stream (and could
-        // fail, leaving this one invalid).
-        SkASSERT(false);
-        return NULL;
-    }
-
-private:
-    JavaInputStreamAdaptor* fAdaptor;
-    const size_t            fLength;
-};
-
-static jclass   gByteArrayInputStream_Clazz;
-static jfieldID gCountField;
-static jfieldID gPosField;
-
-/**
- *  If jstream is a ByteArrayInputStream, return its remaining length. Otherwise
- *  return 0.
- */
-static size_t get_length_from_byte_array_stream(JNIEnv* env, jobject jstream) {
-    if (env->IsInstanceOf(jstream, gByteArrayInputStream_Clazz)) {
-        // Return the remaining length, to keep the same behavior of using the rest of the
-        // stream.
-        return env->GetIntField(jstream, gCountField) - env->GetIntField(jstream, gPosField);
-    }
-    return 0;
-}
-
-/**
- *  If jstream is a class that has a length, return it. Otherwise
- *  return 0.
- *  Only checks for a set of subclasses.
- */
-static size_t get_length_if_supported(JNIEnv* env, jobject jstream) {
-    size_t len = get_length_from_byte_array_stream(env, jstream);
-    if (len > 0) {
-        return len;
-    }
-    return 0;
-}
-
-SkStreamRewindable* GetRewindableStream(JNIEnv* env, jobject stream,
-                                        jbyteArray storage) {
-    SkAutoTUnref<SkStream> adaptor(CreateJavaInputStreamAdaptor(env, stream, storage));
-    if (NULL == adaptor.get()) {
-        return NULL;
-    }
-
-    const size_t length = get_length_if_supported(env, stream);
-    if (length > 0 && env->CallBooleanMethod(stream, gInputStream_markSupportedMethodID)) {
-        // Set the readLimit for mark to the end of the stream, so it can
-        // be rewound regardless of how much has been read.
-        env->CallVoidMethod(stream, gInputStream_markMethodID, length);
-        // RewindableJavaStream will unref adaptor when it is destroyed.
-        return new RewindableJavaStream(static_cast<JavaInputStreamAdaptor*>(adaptor.detach()),
-                                        length);
-    }
-
-    return adaptor_to_mem_stream(adaptor.get());
-}
-
-static jclass       gAssetInputStream_Clazz;
-static jmethodID    gGetAssetIntMethodID;
-
-android::AssetStreamAdaptor* CheckForAssetStream(JNIEnv* env, jobject jstream) {
-    if (!env->IsInstanceOf(jstream, gAssetInputStream_Clazz)) {
-        return NULL;
-    }
-
-    jint jasset = env->CallIntMethod(jstream, gGetAssetIntMethodID);
-    android::Asset* a = reinterpret_cast<android::Asset*>(jasset);
-    if (NULL == a) {
-        jniThrowNullPointerException(env, "NULL native asset");
-        return NULL;
-    }
-    return new android::AssetStreamAdaptor(a);
-}
-
 ///////////////////////////////////////////////////////////////////////////////
 
 static jmethodID    gOutputStream_writeMethodID;
@@ -382,13 +237,6 @@
     return clazz;
 }
 
-static jfieldID getFieldIDCheck(JNIEnv* env, jclass clazz,
-                                const char fieldname[], const char type[]) {
-    jfieldID id = env->GetFieldID(clazz, fieldname, type);
-    SkASSERT(!env->ExceptionCheck());
-    return id;
-}
-
 static jmethodID getMethodIDCheck(JNIEnv* env, jclass clazz,
                                   const char methodname[], const char type[]) {
     jmethodID id = env->GetMethodID(clazz, methodname, type);
@@ -398,25 +246,9 @@
 
 int register_android_graphics_CreateJavaOutputStreamAdaptor(JNIEnv* env) {
     jclass inputStream_Clazz = findClassCheck(env, "java/io/InputStream");
-    gInputStream_resetMethodID = getMethodIDCheck(env, inputStream_Clazz, "reset", "()V");
-    gInputStream_markMethodID = getMethodIDCheck(env, inputStream_Clazz, "mark", "(I)V");
-    gInputStream_markSupportedMethodID = getMethodIDCheck(env, inputStream_Clazz, "markSupported", "()Z");
     gInputStream_readMethodID = getMethodIDCheck(env, inputStream_Clazz, "read", "([BII)I");
     gInputStream_skipMethodID = getMethodIDCheck(env, inputStream_Clazz, "skip", "(J)J");
 
-    gByteArrayInputStream_Clazz = findClassCheck(env, "java/io/ByteArrayInputStream");
-    // Ref gByteArrayInputStream_Clazz so we can continue to refer to it when
-    // calling IsInstance.
-    gByteArrayInputStream_Clazz = (jclass) env->NewGlobalRef(gByteArrayInputStream_Clazz);
-    gCountField = getFieldIDCheck(env, gByteArrayInputStream_Clazz, "count", "I");
-    gPosField = getFieldIDCheck(env, gByteArrayInputStream_Clazz, "pos", "I");
-
-    gAssetInputStream_Clazz = findClassCheck(env, "android/content/res/AssetManager$AssetInputStream");
-    // Ref gAssetInputStream_Clazz so we can continue to refer to it when
-    // calling IsInstance.
-    gAssetInputStream_Clazz = (jclass) env->NewGlobalRef(gAssetInputStream_Clazz);
-    gGetAssetIntMethodID = getMethodIDCheck(env, gAssetInputStream_Clazz, "getAssetInt", "()I");
-
     jclass outputStream_Clazz = findClassCheck(env, "java/io/OutputStream");
     gOutputStream_writeMethodID = getMethodIDCheck(env, outputStream_Clazz, "write", "([BII)V");
     gOutputStream_flushMethodID = getMethodIDCheck(env, outputStream_Clazz, "flush", "()V");
diff --git a/core/jni/android/graphics/CreateJavaOutputStreamAdaptor.h b/core/jni/android/graphics/CreateJavaOutputStreamAdaptor.h
index fcc0c9a..ecd270f 100644
--- a/core/jni/android/graphics/CreateJavaOutputStreamAdaptor.h
+++ b/core/jni/android/graphics/CreateJavaOutputStreamAdaptor.h
@@ -4,10 +4,6 @@
 //#include <android_runtime/AndroidRuntime.h>
 #include "jni.h"
 
-namespace android {
-    class AssetStreamAdaptor;
-}
-
 class SkMemoryStream;
 class SkStream;
 class SkStreamRewindable;
@@ -15,6 +11,7 @@
 
 /**
  *  Return an adaptor from a Java InputStream to an SkStream.
+ *  Does not support rewind.
  *  @param env JNIEnv object.
  *  @param stream Pointer to Java InputStream.
  *  @param storage Java byte array for retrieving data from the
@@ -28,7 +25,7 @@
                                        jbyteArray storage);
 
 /**
- *  Copy a Java InputStream.
+ *  Copy a Java InputStream. The result will be rewindable.
  *  @param env JNIEnv object.
  *  @param stream Pointer to Java InputStream.
  *  @param storage Java byte array for retrieving data from the
@@ -39,32 +36,6 @@
 SkStreamRewindable* CopyJavaInputStream(JNIEnv* env, jobject stream,
                                         jbyteArray storage);
 
-/**
- *  Get a rewindable stream from a Java InputStream.
- *  @param env JNIEnv object.
- *  @param stream Pointer to Java InputStream.
- *  @param storage Java byte array for retrieving data from the
- *      Java InputStream.
- *  @return SkStreamRewindable Either a wrapper around the Java
- *      InputStream, if possible, or a copy which is rewindable.
- *      Since it may be a wrapper, must not be used after the
- *      caller returns, like the result of CreateJavaInputStreamAdaptor.
- */
-SkStreamRewindable* GetRewindableStream(JNIEnv* env, jobject stream,
-                                        jbyteArray storage);
-
-/**
- *  If the Java InputStream is an AssetInputStream, return an adaptor.
- *  This should not be used after the calling function returns, since
- *  the caller may close the asset. Returns NULL if the stream is
- *  not an AssetInputStream.
- *  @param env JNIEnv object.
- *  @param stream Pointer to Java InputStream.
- *  @return AssetStreamAdaptor representing the InputStream, or NULL.
- *      Must not be held onto.
- */
-android::AssetStreamAdaptor* CheckForAssetStream(JNIEnv* env, jobject stream);
-
 SkWStream* CreateJavaOutputStreamAdaptor(JNIEnv* env, jobject stream,
                                          jbyteArray storage);
 #endif
diff --git a/core/jni/android/graphics/Movie.cpp b/core/jni/android/graphics/Movie.cpp
index 2eae841..feb2dec 100644
--- a/core/jni/android/graphics/Movie.cpp
+++ b/core/jni/android/graphics/Movie.cpp
@@ -1,4 +1,5 @@
 #include "ScopedLocalRef.h"
+#include "SkFrontBufferedStream.h"
 #include "SkMovie.h"
 #include "SkStream.h"
 #include "GraphicsJNI.h"
@@ -81,23 +82,33 @@
     c->drawBitmap(b, sx, sy, p);
 }
 
+static jobject movie_decodeAsset(JNIEnv* env, jobject clazz, jint native_asset) {
+    android::Asset* asset = reinterpret_cast<android::Asset*>(native_asset);
+    if (asset == NULL) return NULL;
+    SkAutoTUnref<SkStreamRewindable> stream (new android::AssetStreamAdaptor(asset));
+    SkMovie* moov = SkMovie::DecodeStream(stream.get());
+    return create_jmovie(env, moov);
+}
+
 static jobject movie_decodeStream(JNIEnv* env, jobject clazz, jobject istream) {
 
     NPE_CHECK_RETURN_ZERO(env, istream);
 
-    SkStreamRewindable* strm = CheckForAssetStream(env, istream);
-    jbyteArray byteArray = NULL;
-    ScopedLocalRef<jbyteArray> scoper(env, NULL);
-    if (NULL == strm) {
-        byteArray = env->NewByteArray(16*1024);
-        scoper.reset(byteArray);
-        strm = GetRewindableStream(env, istream, byteArray);
-    }
+    jbyteArray byteArray = env->NewByteArray(16*1024);
+    ScopedLocalRef<jbyteArray> scoper(env, byteArray);
+    SkStream* strm = CreateJavaInputStreamAdaptor(env, istream, byteArray);
     if (NULL == strm) {
         return 0;
     }
 
-    SkMovie* moov = SkMovie::DecodeStream(strm);
+    // Need to buffer enough input to be able to rewind as much as might be read by a decoder
+    // trying to determine the stream's format. The only decoder for movies is GIF, which
+    // will only read 6.
+    // FIXME: Get this number from SkImageDecoder
+    SkAutoTUnref<SkStreamRewindable> bufferedStream(SkFrontBufferedStream::Create(strm, 6));
+    SkASSERT(bufferedStream.get() != NULL);
+
+    SkMovie* moov = SkMovie::DecodeStream(bufferedStream);
     strm->unref();
     return create_jmovie(env, moov);
 }
@@ -135,7 +146,9 @@
     {   "setTime",  "(I)Z", (void*)movie_setTime  },
     {   "draw",     "(Landroid/graphics/Canvas;FFLandroid/graphics/Paint;)V",
                             (void*)movie_draw  },
-    { "decodeStream", "(Ljava/io/InputStream;)Landroid/graphics/Movie;",
+    { "nativeDecodeAsset", "(I)Landroid/graphics/Movie;",
+                            (void*)movie_decodeAsset },
+    { "nativeDecodeStream", "(Ljava/io/InputStream;)Landroid/graphics/Movie;",
                             (void*)movie_decodeStream },
     { "nativeDestructor","(I)V", (void*)movie_destructor },
     { "decodeByteArray", "([BII)Landroid/graphics/Movie;",
diff --git a/graphics/java/android/graphics/BitmapFactory.java b/graphics/java/android/graphics/BitmapFactory.java
index 23606a1..c8ace44 100644
--- a/graphics/java/android/graphics/BitmapFactory.java
+++ b/graphics/java/android/graphics/BitmapFactory.java
@@ -569,10 +569,7 @@
                 final int asset = ((AssetManager.AssetInputStream) is).getAssetInt();
                 bm = nativeDecodeAsset(asset, outPadding, opts);
             } else {
-                byte [] tempStorage = null;
-                if (opts != null) tempStorage = opts.inTempStorage;
-                if (tempStorage == null) tempStorage = new byte[DECODE_BUFFER_SIZE];
-                bm = nativeDecodeStream(is, tempStorage, outPadding, opts);
+                bm = decodeStreamInternal(is, outPadding, opts);
             }
 
             if (bm == null && opts != null && opts.inBitmap != null) {
@@ -588,6 +585,18 @@
     }
 
     /**
+     * Private helper function for decoding an InputStream natively. Buffers the input enough to
+     * do a rewind as needed, and supplies temporary storage if necessary. is MUST NOT be null.
+     */
+    private static Bitmap decodeStreamInternal(InputStream is, Rect outPadding, Options opts) {
+        // ASSERT(is != null);
+        byte [] tempStorage = null;
+        if (opts != null) tempStorage = opts.inTempStorage;
+        if (tempStorage == null) tempStorage = new byte[DECODE_BUFFER_SIZE];
+        return nativeDecodeStream(is, tempStorage, outPadding, opts);
+    }
+
+    /**
      * Decode an input stream into a bitmap. If the input stream is null, or
      * cannot be used to decode a bitmap, the function returns null.
      * The stream's position will be where ever it was after the encoded data
@@ -624,13 +633,8 @@
                 bm = nativeDecodeFileDescriptor(fd, outPadding, opts);
             } else {
                 FileInputStream fis = new FileInputStream(fd);
-                // FIXME: If nativeDecodeStream grabbed the pointer to tempStorage
-                // from Options, this code would not need to be duplicated.
-                byte [] tempStorage = null;
-                if (opts != null) tempStorage = opts.inTempStorage;
-                if (tempStorage == null) tempStorage = new byte[DECODE_BUFFER_SIZE];
                 try {
-                    bm = nativeDecodeStream(fis, tempStorage, outPadding, opts);
+                    bm = decodeStreamInternal(fis, outPadding, opts);
                 } finally {
                     try {
                         fis.close();
diff --git a/graphics/java/android/graphics/Movie.java b/graphics/java/android/graphics/Movie.java
index 4a33453..9419faf 100644
--- a/graphics/java/android/graphics/Movie.java
+++ b/graphics/java/android/graphics/Movie.java
@@ -16,12 +16,13 @@
 
 package android.graphics;
 
+import android.content.res.AssetManager;
 import java.io.InputStream;
 import java.io.FileInputStream;
 
 public class Movie {
     private final int mNativeMovie;
-    
+
     private Movie(int nativeMovie) {
         if (nativeMovie == 0) {
             throw new RuntimeException("native movie creation failed");
@@ -42,7 +43,20 @@
         draw(canvas, x, y, null);
     }
 
-    public static native Movie decodeStream(InputStream is);
+    public static Movie decodeStream(InputStream is) {
+        if (is == null) {
+            return null;
+        }
+        if (is instanceof AssetManager.AssetInputStream) {
+            final int asset = ((AssetManager.AssetInputStream) is).getAssetInt();
+            return nativeDecodeAsset(asset);
+        }
+
+        return nativeDecodeStream(is);
+    }
+
+    private static native Movie nativeDecodeAsset(int asset);
+    private static native Movie nativeDecodeStream(InputStream is);
     public static native Movie decodeByteArray(byte[] data, int offset,
                                                int length);
 
diff --git a/media/java/android/media/ImageReader.java b/media/java/android/media/ImageReader.java
index f9e48d4..1bd32c4 100644
--- a/media/java/android/media/ImageReader.java
+++ b/media/java/android/media/ImageReader.java
@@ -83,7 +83,8 @@
      * @param format
      *            The format of the Image that this reader will produce. This
      *            must be one of the {@link android.graphics.ImageFormat} or
-     *            {@link android.graphics.PixelFormat} constants.
+     *            {@link android.graphics.PixelFormat} constants. Note that
+     *            not all formats is supported, like ImageFormat.NV21.
      * @param maxImages
      *            The maximum number of images the user will want to
      *            access simultaneously. This should be as small as possible to limit
@@ -116,6 +117,11 @@
                 "Maximum outstanding image count must be at least 1");
         }
 
+        if (format == ImageFormat.NV21) {
+            throw new IllegalArgumentException(
+                    "NV21 format is not supported");
+        }
+
         mNumPlanes = getNumPlanesFromFormat();
 
         nativeInit(new WeakReference<ImageReader>(this), width, height, format, maxImages);
diff --git a/media/jni/android_media_ImageReader.cpp b/media/jni/android_media_ImageReader.cpp
index a03dbf3..0030dbd 100644
--- a/media/jni/android_media_ImageReader.cpp
+++ b/media/jni/android_media_ImageReader.cpp
@@ -721,13 +721,18 @@
         return ACQUIRE_NO_BUFFERS;
     }
 
+    if (buffer->format == HAL_PIXEL_FORMAT_YCrCb_420_SP) {
+        jniThrowException(env, "java/lang/UnsupportedOperationException",
+                "NV21 format is not supported by ImageReader");
+        return -1;
+    }
+
     // Check if the left-top corner of the crop rect is origin, we currently assume this point is
     // zero, will revist this once this assumption turns out problematic.
     Point lt = buffer->crop.leftTop();
     if (lt.x != 0 || lt.y != 0) {
-        ALOGE("crop left: %d, top = %d", lt.x, lt.y);
-        jniThrowException(env, "java/lang/UnsupportedOperationException",
-                          "crop left top corner need to at origin");
+        jniThrowExceptionFmt(env, "java/lang/UnsupportedOperationException",
+                "crop left top corner [%d, %d] need to be at origin", lt.x, lt.y);
         return -1;
     }