Merge "Final (hopefully) API cleanup." into honeycomb
diff --git a/api/11.xml b/api/11.xml
index 9dbcf8a..bb69025 100644
--- a/api/11.xml
+++ b/api/11.xml
@@ -60592,6 +60592,17 @@
  visibility="public"
 >
 </field>
+<field name="FEATURE_FAKETOUCH"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;android.hardware.faketouch&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="FEATURE_LIVE_WALLPAPER"
  type="java.lang.String"
  transient="false"
diff --git a/api/current.xml b/api/current.xml
index 9dbcf8a..bb69025 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -60592,6 +60592,17 @@
  visibility="public"
 >
 </field>
+<field name="FEATURE_FAKETOUCH"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;android.hardware.faketouch&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="FEATURE_LIVE_WALLPAPER"
  type="java.lang.String"
  transient="false"
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 6e9cdbe..a589216 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -832,6 +832,18 @@
 
     /**
      * Feature for {@link #getSystemAvailableFeatures} and
+     * {@link #hasSystemFeature}: The device does not have a touch screen, but
+     * does support touch emulation for basic events. For instance, the
+     * device might use a mouse or remote control to drive a cursor, and
+     * emulate basic touch pointer events like down, up, drag, etc. All
+     * devices that support android.hardware.touchscreen or a sub-feature are
+     * presumed to also support faketouch.
+     */
+    @SdkConstant(SdkConstantType.FEATURE)
+    public static final String FEATURE_FAKETOUCH = "android.hardware.faketouch";
+
+    /**
+     * Feature for {@link #getSystemAvailableFeatures} and
      * {@link #hasSystemFeature}: The device supports live wallpapers.
      */
     @SdkConstant(SdkConstantType.FEATURE)
diff --git a/core/java/android/view/GLES20Canvas.java b/core/java/android/view/GLES20Canvas.java
index e47dc93..936e9d2 100644
--- a/core/java/android/view/GLES20Canvas.java
+++ b/core/java/android/view/GLES20Canvas.java
@@ -525,7 +525,7 @@
     @Override
     public void drawArc(RectF oval, float startAngle, float sweepAngle, boolean useCenter,
             Paint paint) {
-        throw new UnsupportedOperationException();
+        // TODO: Implement
     }
 
     @Override
@@ -705,9 +705,14 @@
 
     @Override
     public void drawOval(RectF oval, Paint paint) {
-        throw new UnsupportedOperationException();
+        boolean hasModifier = setupModifiers(paint);
+        nDrawOval(mRenderer, oval.left, oval.top, oval.right, oval.bottom, paint.mNativePaint);
+        if (hasModifier) nResetModifiers(mRenderer); 
     }
 
+    private native void nDrawOval(int renderer, float left, float top, float right, float bottom,
+            int paint);
+
     @Override
     public void drawPaint(Paint paint) {
         final Rect r = mClipBounds;
@@ -765,12 +770,12 @@
 
     @Override
     public void drawPosText(char[] text, int index, int count, float[] pos, Paint paint) {
-        throw new UnsupportedOperationException();
+        // TODO: Implement
     }
 
     @Override
     public void drawPosText(String text, float[] pos, Paint paint) {
-        throw new UnsupportedOperationException();
+        // TODO: Implement
     }
 
     @Override
@@ -879,12 +884,12 @@
     @Override
     public void drawTextOnPath(char[] text, int index, int count, Path path, float hOffset,
             float vOffset, Paint paint) {
-        throw new UnsupportedOperationException();
+        // TODO: Implement
     }
 
     @Override
     public void drawTextOnPath(String text, Path path, float hOffset, float vOffset, Paint paint) {
-        throw new UnsupportedOperationException();
+        // TODO: Implement
     }
 
     @Override
diff --git a/core/java/com/android/internal/service/wallpaper/ImageWallpaper.java b/core/java/com/android/internal/service/wallpaper/ImageWallpaper.java
index d2e53b3..d49902e 100644
--- a/core/java/com/android/internal/service/wallpaper/ImageWallpaper.java
+++ b/core/java/com/android/internal/service/wallpaper/ImageWallpaper.java
@@ -41,6 +41,9 @@
  * Default built-in wallpaper that simply shows a static image.
  */
 public class ImageWallpaper extends WallpaperService {
+    private static final String TAG = "ImageWallpaper";
+    private static final boolean DEBUG = false;
+
     WallpaperManager mWallpaperManager;
     private HandlerThread mThread;
 
@@ -77,10 +80,19 @@
         float mXOffset;
         float mYOffset;
 
+        boolean mVisible = true;
+        boolean mRedrawNeeded;
+        boolean mOffsetsChanged;
+        int mLastXTranslation;
+        int mLastYTranslation;
+
         class WallpaperObserver extends BroadcastReceiver {
             public void onReceive(Context context, Intent intent) {
-                updateWallpaper();
-                drawFrame();
+                synchronized (mLock) {
+                    updateWallpaperLocked();
+                    drawFrameLocked(true, false);
+                }
+
                 // Assume we are the only one using the wallpaper in this
                 // process, and force a GC now to release the old wallpaper.
                 System.gc();
@@ -93,7 +105,10 @@
             IntentFilter filter = new IntentFilter(Intent.ACTION_WALLPAPER_CHANGED);
             mReceiver = new WallpaperObserver();
             registerReceiver(mReceiver, filter);
-            updateWallpaper();
+
+            synchronized (mLock) {
+                updateWallpaperLocked();
+            }
             surfaceHolder.setSizeFromLayout();
         }
 
@@ -105,9 +120,12 @@
 
         @Override
         public void onVisibilityChanged(boolean visible) {
-            drawFrame();
+            synchronized (mLock) {
+                mVisible = visible;
+                drawFrameLocked(false, false);
+            }
         }
-        
+
         @Override
         public void onTouchEvent(MotionEvent event) {
             super.onTouchEvent(event);
@@ -117,15 +135,27 @@
         public void onOffsetsChanged(float xOffset, float yOffset,
                 float xOffsetStep, float yOffsetStep,
                 int xPixels, int yPixels) {
-            mXOffset = xOffset;
-            mYOffset = yOffset;
-            drawFrame();
+            synchronized (mLock) {
+                if (mXOffset != xOffset || mYOffset != yOffset) {
+                    if (DEBUG) {
+                        Log.d(TAG, "Offsets changed to (" + xOffset + "," + yOffset + ").");
+                    }
+                    mXOffset = xOffset;
+                    mYOffset = yOffset;
+                    drawFrameLocked(false, true);
+                } else {
+                    drawFrameLocked(false, false);
+                }
+            }
         }
 
         @Override
         public void onSurfaceChanged(SurfaceHolder holder, int format, int width, int height) {
             super.onSurfaceChanged(holder, format, width, height);
-            drawFrame();
+            
+            synchronized (mLock) {
+                drawFrameLocked(true, false);
+            }
         }
 
         @Override
@@ -137,13 +167,30 @@
         public void onSurfaceDestroyed(SurfaceHolder holder) {
             super.onSurfaceDestroyed(holder);
         }
-        
-        void drawFrame() {
+
+        void drawFrameLocked(boolean redrawNeeded, boolean offsetsChanged) {
+            mRedrawNeeded |= redrawNeeded;
+            mOffsetsChanged |= offsetsChanged;
+
+            if (!mVisible) {
+                if (DEBUG) {
+                    Log.d(TAG, "Suppressed drawFrame since wallpaper is not visible.");
+                }
+                return;
+            }
+            if (!mRedrawNeeded && !mOffsetsChanged) {
+                if (DEBUG) {
+                    Log.d(TAG, "Suppressed drawFrame since redraw is not needed "
+                            + "and offsets have not changed.");
+                }
+                return;
+            }
+
             SurfaceHolder sh = getSurfaceHolder();
             Canvas c = sh.lockCanvas();
             if (c != null) {
-                final Rect frame = sh.getSurfaceFrame();
-                synchronized (mLock) {
+                try {
+                    final Rect frame = sh.getSurfaceFrame();
                     final Drawable background = mBackground;
                     final int dw = frame.width();
                     final int dh = frame.height();
@@ -154,8 +201,22 @@
                     int xPixels = availw < 0 ? (int)(availw*mXOffset+.5f) : (availw/2);
                     int yPixels = availh < 0 ? (int)(availh*mYOffset+.5f) : (availh/2);
 
+                    mOffsetsChanged = false;
+                    if (!mRedrawNeeded) {
+                        if (xPixels == mLastXTranslation && yPixels == mLastYTranslation) {
+                            if (DEBUG) {
+                                Log.d(TAG, "Suppressed drawFrame since the image has not "
+                                        + "actually moved an integral number of pixels.");
+                            }
+                            return;
+                        }
+                    }
+                    mRedrawNeeded = false;
+                    mLastXTranslation = xPixels;
+                    mLastYTranslation = yPixels;
+
                     c.translate(xPixels, yPixels);
-                    if (availw<0 || availh<0) {
+                    if (availw < 0 || availh < 0) {
                         c.save(Canvas.CLIP_SAVE_FLAG);
                         c.clipRect(0, 0, bw, bh, Op.DIFFERENCE);
                         c.drawColor(0xff000000);
@@ -164,35 +225,35 @@
                     if (background != null) {
                         background.draw(c);
                     }
+                } finally {
+                    sh.unlockCanvasAndPost(c);
                 }
-                sh.unlockCanvasAndPost(c);
             }
         }
 
-        void updateWallpaper() {
-            synchronized (mLock) {
-                Throwable exception = null;
+        void updateWallpaperLocked() {
+            Throwable exception = null;
+            try {
+                mBackground = mWallpaperManager.getFastDrawable();
+            } catch (RuntimeException e) {
+                exception = e;
+            } catch (OutOfMemoryError e) {
+                exception = e;
+            }
+            if (exception != null) {
+                mBackground = null;
+                // Note that if we do fail at this, and the default wallpaper can't
+                // be loaded, we will go into a cycle.  Don't do a build where the
+                // default wallpaper can't be loaded.
+                Log.w(TAG, "Unable to load wallpaper!", exception);
                 try {
-                    mBackground = mWallpaperManager.getFastDrawable();
-                } catch (RuntimeException e) {
-                    exception = e;
-                } catch (OutOfMemoryError e) {
-                    exception = e;
-                }
-                if (exception != null) {
-                    mBackground = null;
-                    // Note that if we do fail at this, and the default wallpaper can't
-                    // be loaded, we will go into a cycle.  Don't do a build where the
-                    // default wallpaper can't be loaded.
-                    Log.w("ImageWallpaper", "Unable to load wallpaper!", exception);
-                    try {
-                        mWallpaperManager.clear();
-                    } catch (IOException ex) {
-                        // now we're really screwed.
-                        Log.w("ImageWallpaper", "Unable reset to default wallpaper!", ex);
-                    }
+                    mWallpaperManager.clear();
+                } catch (IOException ex) {
+                    // now we're really screwed.
+                    Log.w(TAG, "Unable reset to default wallpaper!", ex);
                 }
             }
+            mRedrawNeeded = true;
         }
     }
 }
diff --git a/core/jni/android_view_GLES20Canvas.cpp b/core/jni/android_view_GLES20Canvas.cpp
index 554e336f..2daffbb 100644
--- a/core/jni/android_view_GLES20Canvas.cpp
+++ b/core/jni/android_view_GLES20Canvas.cpp
@@ -326,6 +326,12 @@
     renderer->drawCircle(x, y, radius, paint);
 }
 
+static void android_view_GLES20Canvas_drawOval(JNIEnv* env, jobject canvas,
+        OpenGLRenderer* renderer, jfloat left, jfloat top, jfloat right, jfloat bottom,
+        SkPaint* paint) {
+    renderer->drawOval(left, top, right, bottom, paint);
+}
+
 static void android_view_GLES20Canvas_drawRects(JNIEnv* env, jobject canvas,
         OpenGLRenderer* renderer, SkRegion* region, SkPaint* paint) {
     SkRegion::Iterator it(*region);
@@ -602,6 +608,7 @@
     { "nDrawRects",         "(III)V",          (void*) android_view_GLES20Canvas_drawRects },
     { "nDrawRoundRect",     "(IFFFFFFI)V",     (void*) android_view_GLES20Canvas_drawRoundRect },
     { "nDrawCircle",        "(IFFFI)V",        (void*) android_view_GLES20Canvas_drawCircle },
+    { "nDrawOval",          "(IFFFFI)V",       (void*) android_view_GLES20Canvas_drawOval },
     { "nDrawPath",          "(III)V",          (void*) android_view_GLES20Canvas_drawPath },
     { "nDrawLines",         "(I[FIII)V",       (void*) android_view_GLES20Canvas_drawLines },
 
diff --git a/libs/hwui/Caches.h b/libs/hwui/Caches.h
index 24585d5..3bac422 100644
--- a/libs/hwui/Caches.h
+++ b/libs/hwui/Caches.h
@@ -162,6 +162,8 @@
     PathCache pathCache;
     RoundRectShapeCache roundRectShapeCache;
     CircleShapeCache circleShapeCache;
+    OvalShapeCache ovalShapeCache;
+    RectShapeCache rectShapeCache;
     PatchCache patchCache;
     TextDropShadowCache dropShadowCache;
     FboCache fboCache;
diff --git a/libs/hwui/DisplayListRenderer.cpp b/libs/hwui/DisplayListRenderer.cpp
index 58ef7b3..8714997 100644
--- a/libs/hwui/DisplayListRenderer.cpp
+++ b/libs/hwui/DisplayListRenderer.cpp
@@ -107,6 +107,7 @@
     "DrawRect",
     "DrawRoundRect",
     "DrawCircle",
+    "DrawOval",
     "DrawPath",
     "DrawLines",
     "DrawText",
@@ -358,6 +359,10 @@
                 renderer.drawCircle(getFloat(), getFloat(), getFloat(), getPaint());
             }
             break;
+            case DrawOval: {
+                renderer.drawOval(getFloat(), getFloat(), getFloat(), getFloat(), getPaint());
+            }
+            break;
             case DrawPath: {
                 renderer.drawPath(getPath(), getPaint());
             }
@@ -663,6 +668,13 @@
     addPaint(paint);
 }
 
+void DisplayListRenderer::drawOval(float left, float top, float right, float bottom,
+        SkPaint* paint) {
+    addOp(DisplayList::DrawOval);
+    addBounds(left, top, right, bottom);
+    addPaint(paint);
+}
+
 void DisplayListRenderer::drawPath(SkPath* path, SkPaint* paint) {
     addOp(DisplayList::DrawPath);
     addPath(path);
diff --git a/libs/hwui/DisplayListRenderer.h b/libs/hwui/DisplayListRenderer.h
index 68e4359..8183e25 100644
--- a/libs/hwui/DisplayListRenderer.h
+++ b/libs/hwui/DisplayListRenderer.h
@@ -113,6 +113,7 @@
         DrawRect,
         DrawRoundRect,
         DrawCircle,
+        DrawOval,
         DrawPath,
         DrawLines,
         DrawText,
@@ -279,6 +280,7 @@
     void drawRoundRect(float left, float top, float right, float bottom,
             float rx, float ry, SkPaint* paint);
     void drawCircle(float x, float y, float radius, SkPaint* paint);
+    void drawOval(float left, float top, float right, float bottom, SkPaint* paint);
     void drawPath(SkPath* path, SkPaint* paint);
     void drawLines(float* points, int count, SkPaint* paint);
     void drawText(const char* text, int bytesCount, int count, float x, float y, SkPaint* paint);
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index 92aa4bd..99c0600 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -1360,14 +1360,7 @@
     drawColorRect(clip.left, clip.top, clip.right, clip.bottom, color, mode, true);
 }
 
-void OpenGLRenderer::drawRoundRect(float left, float top, float right, float bottom,
-        float rx, float ry, SkPaint* paint) {
-    if (mSnapshot->isIgnored()) return;
-
-    glActiveTexture(gTextureUnits[0]);
-
-    const PathTexture* texture = mCaches.roundRectShapeCache.getRoundRect(
-            right - left, bottom - top, rx, ry, paint);
+void OpenGLRenderer::drawShape(float left, float top, const PathTexture* texture, SkPaint* paint) {
     if (!texture) return;
     const AutoTexture autoCleanup(texture);
 
@@ -1377,22 +1370,47 @@
     drawPathTexture(texture, x, y, paint);
 }
 
+void OpenGLRenderer::drawRoundRect(float left, float top, float right, float bottom,
+        float rx, float ry, SkPaint* paint) {
+    if (mSnapshot->isIgnored()) return;
+
+    glActiveTexture(gTextureUnits[0]);
+    const PathTexture* texture = mCaches.roundRectShapeCache.getRoundRect(
+            right - left, bottom - top, rx, ry, paint);
+    drawShape(left, top, texture, paint);
+}
+
 void OpenGLRenderer::drawCircle(float x, float y, float radius, SkPaint* paint) {
     if (mSnapshot->isIgnored()) return;
 
     glActiveTexture(gTextureUnits[0]);
-
     const PathTexture* texture = mCaches.circleShapeCache.getCircle(radius, paint);
-    if (!texture) return;
-    const AutoTexture autoCleanup(texture);
+    drawShape(x - radius, y - radius, texture, paint);
+}
 
-    const float left = (x - radius) + texture->left - texture->offset;
-    const float top = (y - radius) + texture->top - texture->offset;
+void OpenGLRenderer::drawOval(float left, float top, float right, float bottom, SkPaint* paint) {
+    if (mSnapshot->isIgnored()) return;
 
-    drawPathTexture(texture, left, top, paint);
+    glActiveTexture(gTextureUnits[0]);
+    const PathTexture* texture = mCaches.ovalShapeCache.getOval(right - left, bottom - top, paint);
+    drawShape(left, top, texture, paint);
+}
+
+void OpenGLRenderer::drawRectAsShape(float left, float top, float right, float bottom,
+        SkPaint* paint) {
+    if (mSnapshot->isIgnored()) return;
+
+    glActiveTexture(gTextureUnits[0]);
+    const PathTexture* texture = mCaches.rectShapeCache.getRect(right - left, bottom - top, paint);
+    drawShape(left, top, texture, paint);
 }
 
 void OpenGLRenderer::drawRect(float left, float top, float right, float bottom, SkPaint* p) {
+    if (p->getStyle() != SkPaint::kFill_Style) {
+        drawRectAsShape(left, top, right, bottom, p);
+        return;
+    }
+
     if (quickReject(left, top, right, bottom)) {
         return;
     }
@@ -1706,12 +1724,17 @@
 
         if (underlineWidth > 0.0f) {
             const float textSize = paint->getTextSize();
-            const float strokeWidth = textSize * kStdUnderline_Thickness;
+            // TODO: Support stroke width < 1.0f when we have AA lines
+            const float strokeWidth = fmax(textSize * kStdUnderline_Thickness, 1.0f);
 
             const float left = x - offsetX;
             float top = 0.0f;
 
-            const int pointsCount = 4 * (flags & SkPaint::kStrikeThruText_Flag ? 2 : 1);
+            int linesCount = 0;
+            if (flags & SkPaint::kUnderlineText_Flag) linesCount++;
+            if (flags & SkPaint::kStrikeThruText_Flag) linesCount++;
+
+            const int pointsCount = 4 * linesCount;
             float points[pointsCount];
             int currentPoint = 0;
 
diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h
index 42e93ad..30cf102 100644
--- a/libs/hwui/OpenGLRenderer.h
+++ b/libs/hwui/OpenGLRenderer.h
@@ -112,6 +112,7 @@
     virtual void drawRoundRect(float left, float top, float right, float bottom,
             float rx, float ry, SkPaint* paint);
     virtual void drawCircle(float x, float y, float radius, SkPaint* paint);
+    virtual void drawOval(float left, float top, float right, float bottom, SkPaint* paint);
     virtual void drawPath(SkPath* path, SkPaint* paint);
     virtual void drawLines(float* points, int count, SkPaint* paint);
     virtual void drawText(const char* text, int bytesCount, int count, float x, float y,
@@ -277,6 +278,9 @@
     void drawColorRect(float left, float top, float right, float bottom,
             int color, SkXfermode::Mode mode, bool ignoreTransform = false);
 
+    void drawShape(float left, float top, const PathTexture* texture, SkPaint* paint);
+    void drawRectAsShape(float left, float top, float right, float bottom, SkPaint* p);
+
     /**
      * Draws a textured rectangle with the specified texture. The specified coordinates
      * are transformed by the current snapshot's transform matrix.
diff --git a/libs/hwui/ShapeCache.cpp b/libs/hwui/ShapeCache.cpp
index b78eecb..da86075 100644
--- a/libs/hwui/ShapeCache.cpp
+++ b/libs/hwui/ShapeCache.cpp
@@ -68,5 +68,51 @@
     return texture;
 }
 
+///////////////////////////////////////////////////////////////////////////////
+// Ovals
+///////////////////////////////////////////////////////////////////////////////
+
+OvalShapeCache::OvalShapeCache(): ShapeCache<OvalShapeCacheEntry>(
+        "oval", PROPERTY_SHAPE_CACHE_SIZE, DEFAULT_SHAPE_CACHE_SIZE) {
+}
+
+PathTexture* OvalShapeCache::getOval(float width, float height, SkPaint* paint) {
+    OvalShapeCacheEntry entry(width, height, paint);
+    PathTexture* texture = get(entry);
+
+    if (!texture) {
+        SkPath path;
+        SkRect r;
+        r.set(0.0f, 0.0f, width, height);
+        path.addOval(r, SkPath::kCW_Direction);
+
+        texture = addTexture(entry, &path, paint);
+    }
+
+    return texture;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Rects
+///////////////////////////////////////////////////////////////////////////////
+
+RectShapeCache::RectShapeCache(): ShapeCache<RectShapeCacheEntry>(
+        "rect", PROPERTY_SHAPE_CACHE_SIZE, DEFAULT_SHAPE_CACHE_SIZE) {
+}
+
+PathTexture* RectShapeCache::getRect(float width, float height, SkPaint* paint) {
+    RectShapeCacheEntry entry(width, height, paint);
+    PathTexture* texture = get(entry);
+
+    if (!texture) {
+        SkPath path;
+        path.addRect(0.0f, 0.0f, width, height, SkPath::kCW_Direction);
+
+        texture = addTexture(entry, &path, paint);
+    }
+
+    return texture;
+}
+
 }; // namespace uirenderer
 }; // namespace android
diff --git a/libs/hwui/ShapeCache.h b/libs/hwui/ShapeCache.h
index c627931..a4aff9d 100644
--- a/libs/hwui/ShapeCache.h
+++ b/libs/hwui/ShapeCache.h
@@ -76,6 +76,7 @@
 struct ShapeCacheEntry {
     enum ShapeType {
         kShapeNone,
+        kShapeRect,
         kShapeRoundRect,
         kShapeCircle,
         kShapeOval,
@@ -216,6 +217,70 @@
     uint32_t mRadius;
 }; // CircleShapeCacheEntry
 
+struct OvalShapeCacheEntry: public ShapeCacheEntry {
+    OvalShapeCacheEntry(float width, float height, SkPaint* paint):
+            ShapeCacheEntry(ShapeCacheEntry::kShapeOval, paint) {
+        mWidth = *(uint32_t*) &width;
+        mHeight = *(uint32_t*) &height;
+    }
+
+    OvalShapeCacheEntry(): ShapeCacheEntry() {
+        mWidth = mHeight = 0;
+    }
+
+    OvalShapeCacheEntry(const OvalShapeCacheEntry& entry):
+            ShapeCacheEntry(entry) {
+        mWidth = entry.mWidth;
+        mHeight = entry.mHeight;
+    }
+
+    bool lessThan(const ShapeCacheEntry& r) const {
+        const OvalShapeCacheEntry& rhs = (const OvalShapeCacheEntry&) r;
+        LTE_INT(mWidth) {
+            LTE_INT(mHeight) {
+                return false;
+            }
+        }
+        return false;
+    }
+
+private:
+    uint32_t mWidth;
+    uint32_t mHeight;
+}; // OvalShapeCacheEntry
+
+struct RectShapeCacheEntry: public ShapeCacheEntry {
+    RectShapeCacheEntry(float width, float height, SkPaint* paint):
+            ShapeCacheEntry(ShapeCacheEntry::kShapeRect, paint) {
+        mWidth = *(uint32_t*) &width;
+        mHeight = *(uint32_t*) &height;
+    }
+
+    RectShapeCacheEntry(): ShapeCacheEntry() {
+        mWidth = mHeight = 0;
+    }
+
+    RectShapeCacheEntry(const RectShapeCacheEntry& entry):
+            ShapeCacheEntry(entry) {
+        mWidth = entry.mWidth;
+        mHeight = entry.mHeight;
+    }
+
+    bool lessThan(const ShapeCacheEntry& r) const {
+        const RectShapeCacheEntry& rhs = (const RectShapeCacheEntry&) r;
+        LTE_INT(mWidth) {
+            LTE_INT(mHeight) {
+                return false;
+            }
+        }
+        return false;
+    }
+
+private:
+    uint32_t mWidth;
+    uint32_t mHeight;
+}; // RectShapeCacheEntry
+
 /**
  * A simple LRU shape cache. The cache has a maximum size expressed in bytes.
  * Any texture added to the cache causing the cache to grow beyond the maximum
@@ -289,8 +354,21 @@
     CircleShapeCache();
 
     PathTexture* getCircle(float radius, SkPaint* paint);
-}; // class RoundRectShapeCache
+}; // class CircleShapeCache
 
+class OvalShapeCache: public ShapeCache<OvalShapeCacheEntry> {
+public:
+    OvalShapeCache();
+
+    PathTexture* getOval(float width, float height, SkPaint* paint);
+}; // class OvalShapeCache
+
+class RectShapeCache: public ShapeCache<RectShapeCacheEntry> {
+public:
+    RectShapeCache();
+
+    PathTexture* getRect(float width, float height, SkPaint* paint);
+}; // class RectShapeCache
 
 ///////////////////////////////////////////////////////////////////////////////
 // Constructors/destructor
diff --git a/libs/hwui/TextureCache.cpp b/libs/hwui/TextureCache.cpp
index 6fc2ddb..e560b8f 100644
--- a/libs/hwui/TextureCache.cpp
+++ b/libs/hwui/TextureCache.cpp
@@ -60,7 +60,7 @@
     mCache.setOnEntryRemovedListener(this);
 
     glGetIntegerv(GL_MAX_TEXTURE_SIZE, &mMaxTextureSize);
-    LOGD("    Maximum texture dimension is %d pixels", mMaxTextureSize);
+    INIT_LOGD("    Maximum texture dimension is %d pixels", mMaxTextureSize);
 
     mDebugEnabled = readDebugLevel() & kDebugCaches;
 }
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index 747242f..0d0e89c 100755
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -2481,10 +2481,12 @@
                     return mSeascapeRotation;
                 case ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE:
                     //return either landscape rotation based on the sensor
-                    mOrientationListener.setAllow180Rotation(false);
+                    mOrientationListener.setAllow180Rotation(
+                            isLandscapeOrSeascape(Surface.ROTATION_180));
                     return getCurrentLandscapeRotation(lastRotation);
                 case ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT:
-                    mOrientationListener.setAllow180Rotation(true);
+                    mOrientationListener.setAllow180Rotation(
+                            !isLandscapeOrSeascape(Surface.ROTATION_180));
                     return getCurrentPortraitRotation(lastRotation);
             }
 
diff --git a/services/java/com/android/server/WindowManagerService.java b/services/java/com/android/server/WindowManagerService.java
index ac3b96b..8b235cf 100644
--- a/services/java/com/android/server/WindowManagerService.java
+++ b/services/java/com/android/server/WindowManagerService.java
@@ -10313,11 +10313,8 @@
                             + ": new=" + w.mShownFrame + ", old="
                             + w.mLastShownFrame);
 
-                    boolean resize;
                     int width, height;
                     if ((w.mAttrs.flags & w.mAttrs.FLAG_SCALED) != 0) {
-                        resize = w.mLastRequestedWidth != w.mRequestedWidth ||
-                        w.mLastRequestedHeight != w.mRequestedHeight;
                         // for a scaled surface, we just want to use
                         // the requested size.
                         width  = w.mRequestedWidth;
@@ -10325,58 +10322,61 @@
                         w.mLastRequestedWidth = width;
                         w.mLastRequestedHeight = height;
                         w.mLastShownFrame.set(w.mShownFrame);
-                        try {
-                            if (SHOW_TRANSACTIONS) logSurface(w,
-                                    "POS " + w.mShownFrame.left
-                                    + ", " + w.mShownFrame.top, null);
-                            w.mSurfaceX = w.mShownFrame.left;
-                            w.mSurfaceY = w.mShownFrame.top;
-                            w.mSurface.setPosition(w.mShownFrame.left, w.mShownFrame.top);
-                        } catch (RuntimeException e) {
-                            Slog.w(TAG, "Error positioning surface in " + w, e);
-                            if (!recoveringMemory) {
-                                reclaimSomeSurfaceMemoryLocked(w, "position");
-                            }
-                        }
                     } else {
-                        resize = !w.mLastShownFrame.equals(w.mShownFrame);
                         width = w.mShownFrame.width();
                         height = w.mShownFrame.height();
                         w.mLastShownFrame.set(w.mShownFrame);
                     }
 
-                    if (resize) {
-                        if (width < 1) width = 1;
-                        if (height < 1) height = 1;
-                        if (w.mSurface != null) {
+                    if (w.mSurface != null) {
+                        if (w.mSurfaceX != w.mShownFrame.left
+                                || w.mSurfaceY != w.mShownFrame.top) {
                             try {
                                 if (SHOW_TRANSACTIONS) logSurface(w,
-                                        "POS " + w.mShownFrame.left + ","
-                                        + w.mShownFrame.top + " SIZE "
-                                        + w.mShownFrame.width() + "x"
+                                        "POS " + w.mShownFrame.left
+                                        + ", " + w.mShownFrame.top, null);
+                                w.mSurfaceX = w.mShownFrame.left;
+                                w.mSurfaceY = w.mShownFrame.top;
+                                w.mSurface.setPosition(w.mShownFrame.left, w.mShownFrame.top);
+                            } catch (RuntimeException e) {
+                                Slog.w(TAG, "Error positioning surface of " + w
+                                        + " pos=(" + w.mShownFrame.left
+                                        + "," + w.mShownFrame.top + ")", e);
+                                if (!recoveringMemory) {
+                                    reclaimSomeSurfaceMemoryLocked(w, "position");
+                                }
+                            }
+                        }
+
+                        if (width < 1) {
+                            width = 1;
+                        }
+                        if (height < 1) {
+                            height = 1;
+                        }
+
+                        if (w.mSurfaceW != width || w.mSurfaceH != height) {
+                            try {
+                                if (SHOW_TRANSACTIONS) logSurface(w,
+                                        "SIZE " + w.mShownFrame.width() + "x"
                                         + w.mShownFrame.height(), null);
                                 w.mSurfaceResized = true;
                                 w.mSurfaceW = width;
                                 w.mSurfaceH = height;
                                 w.mSurface.setSize(width, height);
-                                w.mSurfaceX = w.mShownFrame.left;
-                                w.mSurfaceY = w.mShownFrame.top;
-                                w.mSurface.setPosition(w.mShownFrame.left,
-                                        w.mShownFrame.top);
                             } catch (RuntimeException e) {
                                 // If something goes wrong with the surface (such
                                 // as running out of memory), don't take down the
                                 // entire system.
-                                Slog.e(TAG, "Failure updating surface of " + w
-                                        + " size=(" + width + "x" + height
-                                        + "), pos=(" + w.mShownFrame.left
-                                        + "," + w.mShownFrame.top + ")", e);
+                                Slog.e(TAG, "Error resizing surface of " + w
+                                        + " size=(" + width + "x" + height + ")", e);
                                 if (!recoveringMemory) {
                                     reclaimSomeSurfaceMemoryLocked(w, "size");
                                 }
                             }
                         }
                     }
+
                     if (!w.mAppFreezing && w.mLayoutSeq == mLayoutSeq) {
                         w.mContentInsetsChanged =
                             !w.mLastContentInsets.equals(w.mContentInsets);
@@ -10393,11 +10393,21 @@
                         if (localLOGV) Slog.v(TAG, "Resizing " + w
                                 + ": configChanged=" + configChanged
                                 + " last=" + w.mLastFrame + " frame=" + w.mFrame);
-                        if (!w.mLastFrame.equals(w.mFrame)
+                        boolean frameChanged = !w.mLastFrame.equals(w.mFrame);
+                        if (frameChanged
                                 || w.mContentInsetsChanged
                                 || w.mVisibleInsetsChanged
                                 || w.mSurfaceResized
                                 || configChanged) {
+                            if (DEBUG_RESIZE || DEBUG_ORIENTATION) {
+                                Slog.v(TAG, "Resize reasons: "
+                                        + "frameChanged=" + frameChanged
+                                        + " contentInsetsChanged=" + w.mContentInsetsChanged
+                                        + " visibleInsetsChanged=" + w.mVisibleInsetsChanged
+                                        + " surfaceResized=" + w.mSurfaceResized
+                                        + " configChanged=" + configChanged);
+                            }
+
                             w.mLastFrame.set(w.mFrame);
                             w.mLastContentInsets.set(w.mContentInsets);
                             w.mLastVisibleInsets.set(w.mVisibleInsets);
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/ShapesActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/ShapesActivity.java
index 536a669..ddf43d7 100644
--- a/tests/HwAccelerationTest/src/com/android/test/hwui/ShapesActivity.java
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/ShapesActivity.java
@@ -38,6 +38,7 @@
         private Paint mStrokePaint;
         private Paint mFillPaint;
         private RectF mRect;
+        private RectF mOval;
 
         ShapesView(Context c) {
             super(c);
@@ -60,6 +61,8 @@
             mFillPaint.setAntiAlias(true);
             mFillPaint.setColor(0xff0000ff);
             mFillPaint.setStyle(Paint.Style.FILL);
+
+            mOval = new RectF(0.0f, 0.0f, 80.0f, 45.0f);
         }
 
         @Override
@@ -87,6 +90,28 @@
             canvas.translate(0.0f, 110.0f);
             canvas.drawCircle(80.0f, 45.0f, 45.0f, mFillPaint);
             canvas.restore();
+
+            canvas.save();
+            canvas.translate(450.0f, 50.0f);
+            canvas.drawOval(mOval, mNormalPaint);
+
+            canvas.translate(0.0f, 110.0f);
+            canvas.drawOval(mOval, mStrokePaint);
+
+            canvas.translate(0.0f, 110.0f);
+            canvas.drawOval(mOval, mFillPaint);
+            canvas.restore();
+
+            canvas.save();
+            canvas.translate(650.0f, 50.0f);
+            canvas.drawRect(0.0f, 0.0f, 160.0f, 90.0f, mNormalPaint);
+
+            canvas.translate(0.0f, 110.0f);
+            canvas.drawRect(0.0f, 0.0f, 160.0f, 90.0f, mStrokePaint);
+
+            canvas.translate(0.0f, 110.0f);
+            canvas.drawRect(0.0f, 0.0f, 160.0f, 90.0f, mFillPaint);
+            canvas.restore();
         }
     }
 }