Merge "Add more check before using the DRM manager client."
diff --git a/api/current.xml b/api/current.xml
index bd86302..ea86e3b 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -76419,6 +76419,17 @@
  visibility="public"
 >
 </method>
+<method name="getGenerationId"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
 <method name="getHeight"
  return="int"
  abstract="false"
@@ -76636,6 +76647,19 @@
  visibility="public"
 >
 </method>
+<method name="sameAs"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="other" type="android.graphics.Bitmap">
+</parameter>
+</method>
 <method name="setDensity"
  return="void"
  abstract="false"
@@ -76649,6 +76673,19 @@
 <parameter name="density" type="int">
 </parameter>
 </method>
+<method name="setHasAlpha"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="hasAlpha" type="boolean">
+</parameter>
+</method>
 <method name="setPixel"
  return="void"
  abstract="false"
diff --git a/core/java/android/view/HardwareRenderer.java b/core/java/android/view/HardwareRenderer.java
index 71d55f7..d46dacc 100644
--- a/core/java/android/view/HardwareRenderer.java
+++ b/core/java/android/view/HardwareRenderer.java
@@ -42,10 +42,23 @@
 
     /**
      * Turn on to only refresh the parts of the screen that need updating.
+     * When turned on the property defined by {@link #RENDER_DIRTY_REGIONS_PROPERTY}
+     * must also have the value "true". 
      */
     public static final boolean RENDER_DIRTY_REGIONS = true;
 
     /**
+     * System property used to enable or disable dirty regions invalidation.
+     * This property is only queried if {@link #RENDER_DIRTY_REGIONS} is true.
+     * The default value of this property is assumed to be true.
+     * 
+     * Possible values:
+     * "true", to enable partial invalidates
+     * "false", to disable partial invalidates
+     */
+    static final String RENDER_DIRTY_REGIONS_PROPERTY = "hwui.render_dirty_regions";
+
+    /**
      * Turn on to draw dirty regions every other frame.
      */
     private static final boolean DEBUG_DIRTY_REGION = false;
@@ -113,8 +126,23 @@
      */
     abstract void setup(int width, int height);
 
+    /**
+     * Interface used to receive callbacks whenever a view is drawn by
+     * a hardware renderer instance.
+     */
     interface HardwareDrawCallbacks {
+        /**
+         * Invoked before a view is drawn by a hardware renderer.
+         * 
+         * @param canvas The Canvas used to render the view.
+         */
         void onHardwarePreDraw(Canvas canvas);
+
+        /**
+         * Invoked after a view is drawn by a hardware renderer.
+         * 
+         * @param canvas The Canvas used to render the view.
+         */
         void onHardwarePostDraw(Canvas canvas);
     }
 
@@ -250,6 +278,7 @@
         int mFrameCount;
         Paint mDebugPaint;
 
+        boolean mDirtyRegions;
 
         final int mGlVersion;
         final boolean mTranslucent;
@@ -259,6 +288,9 @@
         GlRenderer(int glVersion, boolean translucent) {
             mGlVersion = glVersion;
             mTranslucent = translucent;
+            final String dirtyProperty = System.getProperty(RENDER_DIRTY_REGIONS_PROPERTY, "true");
+            //noinspection PointlessBooleanExpression,ConstantConditions
+            mDirtyRegions = RENDER_DIRTY_REGIONS && "true".equalsIgnoreCase(dirtyProperty);
         }
 
         /**
@@ -388,10 +420,24 @@
             // We can now initialize EGL for that display
             int[] version = new int[2];
             if (!sEgl.eglInitialize(sEglDisplay, version)) {
-                throw new RuntimeException("eglInitialize failed "
-                        + getEGLErrorString(sEgl.eglGetError()));
+                throw new RuntimeException("eglInitialize failed " +
+                        getEGLErrorString(sEgl.eglGetError()));
             }
+
             sEglConfig = getConfigChooser(mGlVersion).chooseConfig(sEgl, sEglDisplay);
+            if (sEglConfig == null) {
+                // We tried to use EGL_SWAP_BEHAVIOR_PRESERVED_BIT, try again without
+                if (mDirtyRegions) {
+                    mDirtyRegions = false;
+
+                    sEglConfig = getConfigChooser(mGlVersion).chooseConfig(sEgl, sEglDisplay);
+                    if (sEglConfig == null) {
+                        throw new RuntimeException("eglConfig not initialized");
+                    }
+                } else {
+                    throw new RuntimeException("eglConfig not initialized");
+                }
+            }
             
             /*
             * Create an EGL context. We want to do this as rarely as we can, because an
@@ -409,7 +455,7 @@
                 throw new RuntimeException("eglDisplay not initialized");
             }
             if (sEglConfig == null) {
-                throw new RuntimeException("mEglConfig not initialized");
+                throw new RuntimeException("eglConfig not initialized");
             }
             if (Thread.currentThread() != sEglThread) {
                 throw new IllegalStateException("HardwareRenderer cannot be used " 
@@ -452,7 +498,7 @@
                         + getEGLErrorString(sEgl.eglGetError()));
             }
             
-            if (RENDER_DIRTY_REGIONS) {
+            if (mDirtyRegions) {
                 if (!GLES20Canvas.preserveBackBuffer()) {
                     Log.w(LOG_TAG, "Backbuffer cannot be preserved");
                 }
@@ -518,15 +564,14 @@
          * @return An {@link android.view.HardwareRenderer.GlRenderer.EglConfigChooser}.
          */
         EglConfigChooser getConfigChooser(int glVersion) {
-            return new ComponentSizeChooser(glVersion, 8, 8, 8, 8, 0, 0);
+            return new ComponentSizeChooser(glVersion, 8, 8, 8, 8, 0, 0, mDirtyRegions);
         }
 
         @Override
         void draw(View view, View.AttachInfo attachInfo, HardwareDrawCallbacks callbacks,
                 Rect dirty) {
             if (canDraw()) {
-                //noinspection PointlessBooleanExpression,ConstantConditions
-                if (!HardwareRenderer.RENDER_DIRTY_REGIONS) {
+                if (!mDirtyRegions) {
                     dirty = null;
                 }
 
@@ -676,16 +721,16 @@
         static class ComponentSizeChooser extends EglConfigChooser {
             private int[] mValue;
 
-            private int mRedSize;
-            private int mGreenSize;
-            private int mBlueSize;
-            private int mAlphaSize;
-            private int mDepthSize;
-            private int mStencilSize;
+            private final int mRedSize;
+            private final int mGreenSize;
+            private final int mBlueSize;
+            private final int mAlphaSize;
+            private final int mDepthSize;
+            private final int mStencilSize;
+            private final boolean mDirtyRegions;
 
             ComponentSizeChooser(int glVersion, int redSize, int greenSize, int blueSize,
-                    int alphaSize, int depthSize, int stencilSize) {
-                //noinspection PointlessBitwiseExpression
+                    int alphaSize, int depthSize, int stencilSize, boolean dirtyRegions) {
                 super(glVersion, new int[] {
                         EGL10.EGL_RED_SIZE, redSize,
                         EGL10.EGL_GREEN_SIZE, greenSize,
@@ -694,7 +739,7 @@
                         EGL10.EGL_DEPTH_SIZE, depthSize,
                         EGL10.EGL_STENCIL_SIZE, stencilSize,
                         EGL_SURFACE_TYPE, EGL10.EGL_WINDOW_BIT |
-                                (RENDER_DIRTY_REGIONS ? EGL_SWAP_BEHAVIOR_PRESERVED_BIT : 0),
+                                (dirtyRegions ? EGL_SWAP_BEHAVIOR_PRESERVED_BIT : 0),
                         EGL10.EGL_NONE });
                 mValue = new int[1];
                 mRedSize = redSize;
@@ -703,7 +748,8 @@
                 mAlphaSize = alphaSize;
                 mDepthSize = depthSize;
                 mStencilSize = stencilSize;
-           }
+                mDirtyRegions = dirtyRegions;
+            }
 
             @Override
             EGLConfig chooseConfig(EGL10 egl, EGLDisplay display, EGLConfig[] configs) {
@@ -716,7 +762,7 @@
                         int b = findConfigAttrib(egl, display, config, EGL10.EGL_BLUE_SIZE, 0);
                         int a = findConfigAttrib(egl, display, config, EGL10.EGL_ALPHA_SIZE, 0);
                         boolean backBuffer;
-                        if (RENDER_DIRTY_REGIONS) {
+                        if (mDirtyRegions) {
                             int surfaceType = findConfigAttrib(egl, display, config,
                                     EGL_SURFACE_TYPE, 0);
                             backBuffer = (surfaceType & EGL_SWAP_BEHAVIOR_PRESERVED_BIT) != 0;
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 26dab81..88bb9fc 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -2617,8 +2617,8 @@
             newHeight = 0;
             heightWidthRatio = 0;
         }
-        // Actual visible height.
-        int actualViewHeight = getViewHeight();
+        // Actual visible content height.
+        int actualViewHeight = Math.round(getViewHeight() * mZoomManager.getInvScale());
         // Avoid sending another message if the dimensions have not changed.
         if (newWidth != mLastWidthSent || newHeight != mLastHeightSent || force ||
                 actualViewHeight != mLastActualHeightSent) {
diff --git a/graphics/java/android/graphics/Bitmap.java b/graphics/java/android/graphics/Bitmap.java
index c7ae2cf..bd903da 100644
--- a/graphics/java/android/graphics/Bitmap.java
+++ b/graphics/java/android/graphics/Bitmap.java
@@ -200,8 +200,6 @@
      * check if a bitmap has changed.
      * 
      * @return The current generation ID for this bitmap.
-     * 
-     * @hide
      */
     public int getGenerationId() {
         return nativeGenerationId(mNativeBitmap);
@@ -752,7 +750,7 @@
         }
         
         // Scale by tdensity / sdensity, rounding up.
-        return ( (size * tdensity) + (sdensity >> 1) ) / sdensity;
+        return ((size * tdensity) + (sdensity >> 1)) / sdensity;
     }
     
     /**
@@ -790,14 +788,12 @@
     /**
      * Tell the bitmap if all of the pixels are known to be opaque (false)
      * or if some of the pixels may contain non-opaque alpha values (true).
-     * Note, for some configs (e.g. RGB_565) this call is ignore, since it does
-     * not support per-pixel alpha values.
+     * Note, for some configs (e.g. RGB_565) this call is ignored, since it
+     * does not support per-pixel alpha values.
      *
      * This is meant as a drawing hint, as in some cases a bitmap that is known
      * to be opaque can take a faster drawing case than one that may have
      * non-opaque per-pixel alpha values.
-     *
-     * @hide
      */
     public void setHasAlpha(boolean hasAlpha) {
         nativeSetHasAlpha(mNativeBitmap, hasAlpha);
@@ -1066,13 +1062,9 @@
      *  Given another bitmap, return true if it has the same dimensions, config,
      *  and pixel data as this bitmap. If any of those differ, return false.
      *  If other is null, return false.
-     *
-     * @hide (just needed internally right now)
      */
     public boolean sameAs(Bitmap other) {
-        return this == other ||
-              (other != null &&
-               nativeSameAs(mNativeBitmap, other.mNativeBitmap));
+        return this == other || (other != null && nativeSameAs(mNativeBitmap, other.mNativeBitmap));
     }
 
     /**
@@ -1099,7 +1091,13 @@
 
         @Override
         public void finalize() {
-            nativeDestructor(mNativeBitmap);
+            try {
+                super.finalize();
+            } catch (Throwable t) {
+                // Ignore
+            } finally {
+                nativeDestructor(mNativeBitmap);
+            }
         }
     }
 
diff --git a/include/media/stagefright/OMXCodec.h b/include/media/stagefright/OMXCodec.h
index 82948cb..f7d837a 100644
--- a/include/media/stagefright/OMXCodec.h
+++ b/include/media/stagefright/OMXCodec.h
@@ -175,6 +175,7 @@
     int64_t mSeekTimeUs;
     ReadOptions::SeekMode mSeekMode;
     int64_t mTargetTimeUs;
+    bool mOutputPortSettingsChangedPending;
 
     MediaBuffer *mLeftOverBuffer;
 
diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp
index 247ace7..fccd68c 100644
--- a/media/libstagefright/OMXCodec.cpp
+++ b/media/libstagefright/OMXCodec.cpp
@@ -1434,6 +1434,7 @@
       mSeekTimeUs(-1),
       mSeekMode(ReadOptions::SEEK_CLOSEST_SYNC),
       mTargetTimeUs(-1),
+      mOutputPortSettingsChangedPending(false),
       mLeftOverBuffer(NULL),
       mPaused(false),
       mNativeWindow(nativeWindow) {
@@ -2344,6 +2345,14 @@
                     drainInputBuffers();
                     fillOutputBuffers();
                 }
+
+                if (mOutputPortSettingsChangedPending) {
+                    CODEC_LOGV(
+                            "Honoring deferred output port settings change.");
+
+                    mOutputPortSettingsChangedPending = false;
+                    onPortSettingsChanged(kPortIndexOutput);
+                }
             }
 
             break;
@@ -2407,6 +2416,8 @@
 
             CODEC_LOGV("Now Executing.");
 
+            mOutputPortSettingsChangedPending = false;
+
             setState(EXECUTING);
 
             // Buffers will be submitted to the component in the first
@@ -2520,6 +2531,14 @@
 
     CHECK_EQ((int)mState, (int)EXECUTING);
     CHECK_EQ(portIndex, (OMX_U32)kPortIndexOutput);
+    CHECK(!mOutputPortSettingsChangedPending);
+
+    if (mPortStatus[kPortIndexOutput] != ENABLED) {
+        CODEC_LOGV("Deferring output port settings change.");
+        mOutputPortSettingsChangedPending = true;
+        return;
+    }
+
     setState(RECONFIGURING);
 
     if (mQuirks & kNeedsFlushBeforeDisable) {
@@ -2712,6 +2731,7 @@
                 if (srcBuffer->meta_data()->findInt64(
                             kKeyTargetTime, &targetTimeUs)
                         && targetTimeUs >= 0) {
+                    CODEC_LOGV("targetTimeUs = %lld us", targetTimeUs);
                     mTargetTimeUs = targetTimeUs;
                 } else {
                     mTargetTimeUs = -1;
@@ -3385,6 +3405,14 @@
     }
 
     if (seeking) {
+        while (mState == RECONFIGURING) {
+            mBufferFilled.wait(mLock);
+        }
+
+        if (mState != EXECUTING) {
+            return UNKNOWN_ERROR;
+        }
+
         CODEC_LOGV("seeking to %lld us (%.2f secs)", seekTimeUs, seekTimeUs / 1E6);
 
         mSignalledEOS = false;
diff --git a/media/libstagefright/codecs/on2/dec/VPXDecoder.cpp b/media/libstagefright/codecs/on2/dec/VPXDecoder.cpp
index 9433178..489e5ad 100644
--- a/media/libstagefright/codecs/on2/dec/VPXDecoder.cpp
+++ b/media/libstagefright/codecs/on2/dec/VPXDecoder.cpp
@@ -205,7 +205,9 @@
     vpx_image_t *img = vpx_codec_get_frame((vpx_codec_ctx_t *)mCtx, &iter);
 
     if (img == NULL) {
-        LOGI("on2 decoder did not return a frame.");
+        // The VPX format supports "internal-only" frames that are
+        // referenced by future content but never actually displayed, so
+        // this is a perfectly valid scenario.
 
         *out = new MediaBuffer(0);
         return OK;
diff --git a/services/input/tests/InputReader_test.cpp b/services/input/tests/InputReader_test.cpp
index 25030d8..8ec1fd4 100644
--- a/services/input/tests/InputReader_test.cpp
+++ b/services/input/tests/InputReader_test.cpp
@@ -878,7 +878,8 @@
     InstrumentedInputReader(const sp<EventHubInterface>& eventHub,
             const sp<InputReaderPolicyInterface>& policy,
             const sp<InputDispatcherInterface>& dispatcher) :
-            InputReader(eventHub, policy, dispatcher) {
+            InputReader(eventHub, policy, dispatcher),
+            mNextDevice(NULL) {
     }
 
     virtual ~InstrumentedInputReader() {