AI 143160: am: CL 142856 new-new-new-new rotation animation. it may still change one more time.
  Original author: mathias
  Merged from: //branches/cupcake/...

Automated import of CL 143160
diff --git a/libs/surfaceflinger/Android.mk b/libs/surfaceflinger/Android.mk
index 496e271..2212436 100644
--- a/libs/surfaceflinger/Android.mk
+++ b/libs/surfaceflinger/Android.mk
@@ -16,6 +16,7 @@
     LayerBitmap.cpp \
     LayerDim.cpp \
     LayerOrientationAnim.cpp \
+    LayerOrientationAnimRotate.cpp \
     OrientationAnimation.cpp \
     SurfaceFlinger.cpp \
     Tokenizer.cpp \
diff --git a/libs/surfaceflinger/LayerOrientationAnim.cpp b/libs/surfaceflinger/LayerOrientationAnim.cpp
index 2b72d7c..3e4035e 100644
--- a/libs/surfaceflinger/LayerOrientationAnim.cpp
+++ b/libs/surfaceflinger/LayerOrientationAnim.cpp
@@ -22,11 +22,13 @@
 
 #include <utils/Errors.h>
 #include <utils/Log.h>
+#include <utils/StopWatch.h>
 
 #include <core/SkBitmap.h>
 
 #include <ui/EGLDisplaySurface.h>
 
+#include "BlurFilter.h"
 #include "LayerBase.h"
 #include "LayerOrientationAnim.h"
 #include "SurfaceFlinger.h"
@@ -41,22 +43,35 @@
 
 // ---------------------------------------------------------------------------
 
+// Animation...
+const float DURATION = ms2ns(200);
+const float BOUNCES_PER_SECOND = 0.5f;
+//const float BOUNCES_AMPLITUDE = 1.0f/16.0f;
+const float BOUNCES_AMPLITUDE = 0;
+const float DIM_TARGET = 0.40f;
+//#define INTERPOLATED_TIME(_t)   ((_t)*(_t))
+#define INTERPOLATED_TIME(_t)   (_t)
+
+// ---------------------------------------------------------------------------
+
 LayerOrientationAnim::LayerOrientationAnim(
         SurfaceFlinger* flinger, DisplayID display, 
         OrientationAnimation* anim, 
-        const LayerBitmap& bitmap,
-        const LayerBitmap& bitmapIn)
-    : LayerBase(flinger, display), mAnim(anim), 
-      mBitmap(bitmap), mBitmapIn(bitmapIn), 
+        const LayerBitmap& bitmapIn,
+        const LayerBitmap& bitmapOut)
+    : LayerOrientationAnimBase(flinger, display), mAnim(anim), 
+      mBitmapIn(bitmapIn), mBitmapOut(bitmapOut), 
       mTextureName(-1), mTextureNameIn(-1)
 {
+    // blur that texture. 
     mStartTime = systemTime();
     mFinishTime = 0;
     mOrientationCompleted = false;
     mFirstRedraw = false;
     mLastNormalizedTime = 0;
-    mLastScale = 0;
     mNeedsBlending = false;
+    mAlphaInLerp.set(1.0f, DIM_TARGET);
+    mAlphaOutLerp.set(0.5f, 1.0f);
 }
 
 LayerOrientationAnim::~LayerOrientationAnim()
@@ -111,14 +126,8 @@
 
 void LayerOrientationAnim::onDraw(const Region& clip) const
 {
-    // Animation...
-    const float MIN_SCALE = 0.5f;
-    const float DURATION = ms2ns(200);
-    const float BOUNCES_PER_SECOND = 1.618f;
-    const float BOUNCES_AMPLITUDE = 1.0f/32.0f;
-
     const nsecs_t now = systemTime();
-    float scale, alpha;
+    float alphaIn, alphaOut;
     
     if (mOrientationCompleted) {
         if (mFirstRedraw) {
@@ -126,7 +135,7 @@
             
             // make a copy of what's on screen
             copybit_image_t image;
-            mBitmapIn.getBitmapSurface(&image);
+            mBitmapOut.getBitmapSurface(&image);
             const DisplayHardware& hw(graphicPlane(0).displayHardware());
             hw.copyBackToImage(image);
 
@@ -147,37 +156,40 @@
         const float duration = DURATION * mLastNormalizedTime;
         const float normalizedTime = (float(now - mFinishTime) / duration);
         if (normalizedTime <= 1.0f) {
-            const float squaredTime = normalizedTime*normalizedTime;
-            scale = (1.0f - mLastScale)*squaredTime + mLastScale;
-            alpha = (1.0f - normalizedTime);
-            alpha *= alpha;
-            alpha *= alpha;
+            const float interpolatedTime = INTERPOLATED_TIME(normalizedTime);
+            alphaIn = mAlphaInLerp.getOut();
+            alphaOut = mAlphaOutLerp(interpolatedTime);
         } else {
             mAnim->onAnimationFinished();
-            scale = 1.0f;
-            alpha = 0.0f;
+            alphaIn = mAlphaInLerp.getOut();
+            alphaOut = mAlphaOutLerp.getOut();
         }
     } else {
         const float normalizedTime = float(now - mStartTime) / DURATION;
         if (normalizedTime <= 1.0f) {
             mLastNormalizedTime = normalizedTime;
-            const float squaredTime = normalizedTime*normalizedTime;
-            scale = (MIN_SCALE-1.0f)*squaredTime + 1.0f;
-            alpha = 1.0f;
+            const float interpolatedTime = INTERPOLATED_TIME(normalizedTime);
+            alphaIn = mAlphaInLerp(interpolatedTime);
+            alphaOut = 0.0f;
         } else {
             mLastNormalizedTime = 1.0f;
             const float to_seconds = DURATION / seconds(1);
-            const float phi = BOUNCES_PER_SECOND * 
-                    (((normalizedTime - 1.0f) * to_seconds)*M_PI*2);
-            scale = MIN_SCALE + BOUNCES_AMPLITUDE * (1.0f - cosf(phi));
-            alpha = 1.0f;
+            alphaIn = mAlphaInLerp.getOut();
+            if (BOUNCES_AMPLITUDE > 0.0f) {
+                const float phi = BOUNCES_PER_SECOND * 
+                        (((normalizedTime - 1.0f) * to_seconds)*M_PI*2);
+                if (alphaIn > 1.0f) alphaIn = 1.0f;
+                else if (alphaIn < 0.0f) alphaIn = 0.0f;
+                alphaIn += BOUNCES_AMPLITUDE * (1.0f - cosf(phi));
+            }
+            alphaOut = 0.0f;
         }
-        mLastScale = scale;
+        mAlphaOutLerp.setIn(alphaIn);
     }
-    drawScaled(scale, alpha);
+    drawScaled(1.0f, alphaIn, alphaOut);
 }
 
-void LayerOrientationAnim::drawScaled(float f, float alpha) const
+void LayerOrientationAnim::drawScaled(float scale, float alphaIn, float alphaOut) const
 {
     copybit_image_t dst;
     const GraphicPlane& plane(graphicPlane(0));
@@ -188,22 +200,30 @@
     // TODO: with update on demand, we may be able 
     // to not erase the screen at all during the animation 
     if (!mOrientationCompleted) {
-        glDisable(GL_BLEND);
-        glDisable(GL_DITHER);
-        glDisable(GL_SCISSOR_TEST);
-        glClearColor(0,0,0,0);
-        glClear(GL_COLOR_BUFFER_BIT);
+        if (scale==1.0f && (alphaIn>=1.0f || alphaOut>=1.0f)) {
+            // we don't need to erase the screen in that case
+        } else {
+            glDisable(GL_BLEND);
+            glDisable(GL_DITHER);
+            glDisable(GL_SCISSOR_TEST);
+            glClearColor(0,0,0,0);
+            glClear(GL_COLOR_BUFFER_BIT);
+        }
     }
     
-    const int w = dst.w*f; 
-    const int h = dst.h*f; 
+    copybit_image_t src;
+    mBitmapIn.getBitmapSurface(&src);
+
+    copybit_image_t srcOut;
+    mBitmapOut.getBitmapSurface(&srcOut);
+
+    const int w = dst.w*scale; 
+    const int h = dst.h*scale; 
     const int xc = uint32_t(dst.w-w)/2;
     const int yc = uint32_t(dst.h-h)/2;
     const copybit_rect_t drect = { xc, yc, xc+w, yc+h }; 
-
-    copybit_image_t src;
-    mBitmap.getBitmapSurface(&src);
     const copybit_rect_t srect = { 0, 0, src.w, src.h };
+    const Region reg(Rect( drect.l, drect.t, drect.r, drect.b ));
 
     int err = NO_ERROR;
     const int can_use_copybit = canUseCopybit();
@@ -211,19 +231,19 @@
         copybit_device_t* copybit = mFlinger->getBlitEngine();
         copybit->set_parameter(copybit, COPYBIT_TRANSFORM, 0);
         copybit->set_parameter(copybit, COPYBIT_DITHER, COPYBIT_ENABLE);
-
-        if (alpha < 1.0f) {
-            copybit_image_t srcIn;
-            mBitmapIn.getBitmapSurface(&srcIn);
-            region_iterator it(Region(Rect( drect.l, drect.t, drect.r, drect.b )));
-            copybit->set_parameter(copybit, COPYBIT_PLANE_ALPHA, 0xFF);
-            err = copybit->stretch(copybit, &dst, &srcIn, &drect, &srect, &it);
+        
+        if (alphaIn > 0) {
+            region_iterator it(reg);
+            copybit->set_parameter(copybit, COPYBIT_BLUR, COPYBIT_ENABLE);
+            copybit->set_parameter(copybit, COPYBIT_PLANE_ALPHA, int(alphaIn*255));
+            err = copybit->stretch(copybit, &dst, &src, &drect, &srect, &it);
         }
 
-        if (!err && alpha > 0.0f) {
-            region_iterator it(Region(Rect( drect.l, drect.t, drect.r, drect.b )));
-            copybit->set_parameter(copybit, COPYBIT_PLANE_ALPHA, int(alpha*255));
-            err = copybit->stretch(copybit, &dst, &src, &drect, &srect, &it);
+        if (!err && alphaOut > 0.0f) {
+            region_iterator it(reg);
+            copybit->set_parameter(copybit, COPYBIT_BLUR, COPYBIT_DISABLE);
+            copybit->set_parameter(copybit, COPYBIT_PLANE_ALPHA, int(alphaOut*255));
+            err = copybit->stretch(copybit, &dst, &srcOut, &drect, &srect, &it);
         }
         LOGE_IF(err != NO_ERROR, "copybit failed (%s)", strerror(err));
     }
@@ -238,7 +258,7 @@
         t.data = (GGLubyte*)(intptr_t(src.base) + src.offset);
 
         Transform tr;
-        tr.set(f,0,0,f);
+        tr.set(scale,0,0,scale);
         tr.set(xc, yc);
         
         // FIXME: we should not access mVertices and mDrawingState like that,
@@ -254,9 +274,7 @@
             self.mDrawingState.flags |= ISurfaceComposer::eLayerFilter;
         }
 
-        if (alpha < 1.0f) {
-            copybit_image_t src;
-            mBitmapIn.getBitmapSurface(&src);
+        if (alphaIn > 0.0f) {
             t.data = (GGLubyte*)(intptr_t(src.base) + src.offset);
             if (UNLIKELY(mTextureNameIn == -1LU)) {
                 mTextureNameIn = createTexture();
@@ -264,21 +282,21 @@
                 const Region dirty(Rect(t.width, t.height));
                 loadTexture(dirty, mTextureNameIn, t, w, h);
             }
-            self.mDrawingState.alpha = 255;
-            const Region clip(Rect( drect.l, drect.t, drect.r, drect.b ));
-            drawWithOpenGL(clip, mTextureName, t);
+            self.mDrawingState.alpha = int(alphaIn*255);
+            drawWithOpenGL(reg, mTextureNameIn, t);
         }
 
-        t.data = (GGLubyte*)(intptr_t(src.base) + src.offset);
-        if (UNLIKELY(mTextureName == -1LU)) {
-            mTextureName = createTexture();
-            GLuint w=0, h=0;
-            const Region dirty(Rect(t.width, t.height));
-            loadTexture(dirty, mTextureName, t, w, h);
+        if (alphaOut > 0.0f) {
+            t.data = (GGLubyte*)(intptr_t(srcOut.base) + srcOut.offset);
+            if (UNLIKELY(mTextureName == -1LU)) {
+                mTextureName = createTexture();
+                GLuint w=0, h=0;
+                const Region dirty(Rect(t.width, t.height));
+                loadTexture(dirty, mTextureName, t, w, h);
+            }
+            self.mDrawingState.alpha = int(alphaOut*255);
+            drawWithOpenGL(reg, mTextureName, t);
         }
-        self.mDrawingState.alpha = int(alpha*255);
-        const Region clip(Rect( drect.l, drect.t, drect.r, drect.b ));
-        drawWithOpenGL(clip, mTextureName, t);
     }
 }
 
diff --git a/libs/surfaceflinger/LayerOrientationAnim.h b/libs/surfaceflinger/LayerOrientationAnim.h
index 73676859..365c6ae 100644
--- a/libs/surfaceflinger/LayerOrientationAnim.h
+++ b/libs/surfaceflinger/LayerOrientationAnim.h
@@ -30,7 +30,19 @@
 // ---------------------------------------------------------------------------
 class OrientationAnimation;
 
-class LayerOrientationAnim : public LayerBase
+
+class LayerOrientationAnimBase : public LayerBase
+{
+public:
+    LayerOrientationAnimBase(SurfaceFlinger* flinger, DisplayID display)
+        : LayerBase(flinger, display) {
+    }
+    virtual void onOrientationCompleted() = 0;
+};
+
+// ---------------------------------------------------------------------------
+
+class LayerOrientationAnim : public LayerOrientationAnimBase
 {
 public:    
     static const uint32_t typeInfo;
@@ -40,8 +52,8 @@
     
                 LayerOrientationAnim(SurfaceFlinger* flinger, DisplayID display,
                         OrientationAnimation* anim, 
-                        const LayerBitmap& zoomOut,
-                        const LayerBitmap& zoomIn);
+                        const LayerBitmap& bitmapIn,
+                        const LayerBitmap& bitmapOut);
         virtual ~LayerOrientationAnim();
 
             void onOrientationCompleted();
@@ -52,20 +64,45 @@
     virtual bool needsBlending() const;
     virtual bool isSecure() const       { return false; }
 private:
-    void drawScaled(float scale, float alpha) const;
+    void drawScaled(float scale, float alphaIn, float alphaOut) const;
 
+    class Lerp {
+        float in;
+        float outMinusIn;
+    public:
+        Lerp() : in(0), outMinusIn(0) { }
+        Lerp(float in, float out) : in(in), outMinusIn(out-in) { }
+        float getIn() const { return in; };
+        float getOut() const { return in + outMinusIn; }
+        void set(float in, float out) { 
+            this->in = in; 
+            this->outMinusIn = out-in; 
+        }
+        void setIn(float in) { 
+            this->in = in; 
+        }
+        void setOut(float out) { 
+            this->outMinusIn = out - this->in; 
+        }
+        float operator()(float t) const { 
+            return outMinusIn*t + in; 
+        }
+    };
+    
     OrientationAnimation* mAnim;
-    LayerBitmap mBitmap;
     LayerBitmap mBitmapIn;
+    LayerBitmap mBitmapOut;
     nsecs_t mStartTime;
     nsecs_t mFinishTime;
     bool mOrientationCompleted;
     mutable bool mFirstRedraw;
     mutable float mLastNormalizedTime;
-    mutable float mLastScale;
     mutable GLuint  mTextureName;
     mutable GLuint  mTextureNameIn;
     mutable bool mNeedsBlending;
+    
+    mutable Lerp mAlphaInLerp;
+    mutable Lerp mAlphaOutLerp;
 };
 
 // ---------------------------------------------------------------------------
diff --git a/libs/surfaceflinger/LayerOrientationAnimRotate.cpp b/libs/surfaceflinger/LayerOrientationAnimRotate.cpp
new file mode 100644
index 0000000..12d5d80
--- /dev/null
+++ b/libs/surfaceflinger/LayerOrientationAnimRotate.cpp
@@ -0,0 +1,274 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "SurfaceFlinger"
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <utils/Errors.h>
+#include <utils/Log.h>
+
+#include <core/SkBitmap.h>
+
+#include <ui/EGLDisplaySurface.h>
+
+#include "LayerBase.h"
+#include "LayerOrientationAnim.h"
+#include "LayerOrientationAnimRotate.h"
+#include "SurfaceFlinger.h"
+#include "DisplayHardware/DisplayHardware.h"
+#include "OrientationAnimation.h"
+
+namespace android {
+// ---------------------------------------------------------------------------
+
+const uint32_t LayerOrientationAnimRotate::typeInfo = LayerBase::typeInfo | 0x100;
+const char* const LayerOrientationAnimRotate::typeID = "LayerOrientationAnimRotate";
+
+// ---------------------------------------------------------------------------
+
+const float ROTATION = M_PI * 0.5f;
+const float ROTATION_FACTOR = 1.0f; // 1.0 or 2.0
+const float DURATION = ms2ns(200);
+const float BOUNCES_PER_SECOND = 0.8;
+const float BOUNCES_AMPLITUDE = (5.0f/180.f) * M_PI;
+
+LayerOrientationAnimRotate::LayerOrientationAnimRotate(
+        SurfaceFlinger* flinger, DisplayID display, 
+        OrientationAnimation* anim, 
+        const LayerBitmap& bitmap,
+        const LayerBitmap& bitmapIn)
+    : LayerOrientationAnimBase(flinger, display), mAnim(anim), 
+      mBitmap(bitmap), mBitmapIn(bitmapIn), 
+      mTextureName(-1), mTextureNameIn(-1)
+{
+    mStartTime = systemTime();
+    mFinishTime = 0;
+    mOrientationCompleted = false;
+    mFirstRedraw = false;
+    mLastNormalizedTime = 0;
+    mLastAngle = 0;
+    mLastScale = 0;
+    mNeedsBlending = false;
+}
+
+LayerOrientationAnimRotate::~LayerOrientationAnimRotate()
+{
+    if (mTextureName != -1U) {
+        LayerBase::deletedTextures.add(mTextureName);
+    }
+    if (mTextureNameIn != -1U) {
+        LayerBase::deletedTextures.add(mTextureNameIn);
+    }
+}
+
+bool LayerOrientationAnimRotate::needsBlending() const 
+{
+    return mNeedsBlending; 
+}
+
+Point LayerOrientationAnimRotate::getPhysicalSize() const
+{
+    const GraphicPlane& plane(graphicPlane(0));
+    const DisplayHardware& hw(plane.displayHardware());
+    return Point(hw.getWidth(), hw.getHeight());
+}
+
+void LayerOrientationAnimRotate::validateVisibility(const Transform&)
+{
+    const Layer::State& s(drawingState());
+    const Transform tr(s.transform);
+    const Point size(getPhysicalSize());
+    uint32_t w = size.x;
+    uint32_t h = size.y;
+    mTransformedBounds = tr.makeBounds(w, h);
+    mLeft = tr.tx();
+    mTop  = tr.ty();
+    transparentRegionScreen.clear();
+    mTransformed = true;
+    mCanUseCopyBit = false;
+}
+
+void LayerOrientationAnimRotate::onOrientationCompleted()
+{
+    mFinishTime = systemTime();
+    mOrientationCompleted = true;
+    mFirstRedraw = true;
+    mNeedsBlending = true;
+    mFlinger->invalidateLayerVisibility(this);
+}
+
+void LayerOrientationAnimRotate::onDraw(const Region& clip) const
+{
+    // Animation...
+
+    // FIXME: works only for portrait framebuffers
+    const Point size(getPhysicalSize());
+    const float TARGET_SCALE = size.x * (1.0f / size.y);
+    
+    const nsecs_t now = systemTime();
+    float angle, scale, alpha;
+    
+    if (mOrientationCompleted) {
+        if (mFirstRedraw) {
+            // make a copy of what's on screen
+            copybit_image_t image;
+            mBitmapIn.getBitmapSurface(&image);
+            const DisplayHardware& hw(graphicPlane(0).displayHardware());
+            hw.copyBackToImage(image);
+            
+            // FIXME: code below is gross
+            mFirstRedraw = false; 
+            mNeedsBlending = false;
+            LayerOrientationAnimRotate* self(const_cast<LayerOrientationAnimRotate*>(this));
+            mFlinger->invalidateLayerVisibility(self);
+        }
+
+        // make sure pick-up where we left off
+        const float duration = DURATION * mLastNormalizedTime;
+        const float normalizedTime = (float(now - mFinishTime) / duration);
+        if (normalizedTime <= 1.0f) {
+            const float squaredTime = normalizedTime*normalizedTime;
+            angle = (ROTATION*ROTATION_FACTOR - mLastAngle)*squaredTime + mLastAngle;
+            scale = (1.0f - mLastScale)*squaredTime + mLastScale;
+            alpha = normalizedTime;
+        } else {
+            mAnim->onAnimationFinished();
+            angle = ROTATION;
+            alpha = 1.0f;
+            scale = 1.0f;
+        }
+    } else {
+        const float normalizedTime = float(now - mStartTime) / DURATION;
+        if (normalizedTime <= 1.0f) {
+            mLastNormalizedTime = normalizedTime;
+            const float squaredTime = normalizedTime*normalizedTime;
+            angle = ROTATION * squaredTime;
+            scale = (TARGET_SCALE - 1.0f)*squaredTime + 1.0f;
+            alpha = 0;
+        } else {
+            mLastNormalizedTime = 1.0f;
+            angle = ROTATION;
+            if (BOUNCES_AMPLITUDE) {
+                const float to_seconds = DURATION / seconds(1);
+                const float phi = BOUNCES_PER_SECOND * 
+                (((normalizedTime - 1.0f) * to_seconds)*M_PI*2);
+                angle += BOUNCES_AMPLITUDE * sinf(phi);
+            }
+            scale = TARGET_SCALE;
+            alpha = 0;
+        }
+        mLastAngle = angle;
+        mLastScale = scale;
+    }
+    drawScaled(angle, scale, alpha);
+}
+
+void LayerOrientationAnimRotate::drawScaled(float f, float s, float alpha) const
+{
+    copybit_image_t dst;
+    const GraphicPlane& plane(graphicPlane(0));
+    const DisplayHardware& hw(plane.displayHardware());
+    hw.getDisplaySurface(&dst);
+
+    // clear screen
+    // TODO: with update on demand, we may be able 
+    // to not erase the screen at all during the animation 
+    glDisable(GL_BLEND);
+    glDisable(GL_DITHER);
+    glDisable(GL_SCISSOR_TEST);
+    glClearColor(0,0,0,0);
+    glClear(GL_COLOR_BUFFER_BIT);
+    
+    const int w = dst.w; 
+    const int h = dst.h; 
+
+    copybit_image_t src;
+    mBitmap.getBitmapSurface(&src);
+    const copybit_rect_t srect = { 0, 0, src.w, src.h };
+
+
+    GGLSurface t;
+    t.version = sizeof(GGLSurface);
+    t.width  = src.w;
+    t.height = src.h;
+    t.stride = src.w;
+    t.vstride= src.h;
+    t.format = src.format;
+    t.data = (GGLubyte*)(intptr_t(src.base) + src.offset);
+
+    const int targetOrientation = plane.getOrientation(); 
+    if (!targetOrientation) {
+        f = -f;
+    }
+
+    Transform tr;
+    tr.set(f, w*0.5f, h*0.5f);
+    tr.scale(s, w*0.5f, h*0.5f);
+
+    // FIXME: we should not access mVertices and mDrawingState like that,
+    // but since we control the animation, we know it's going to work okay.
+    // eventually we'd need a more formal way of doing things like this.
+    LayerOrientationAnimRotate& self(const_cast<LayerOrientationAnimRotate&>(*this));
+    tr.transform(self.mVertices[0], 0, 0);
+    tr.transform(self.mVertices[1], 0, src.h);
+    tr.transform(self.mVertices[2], src.w, src.h);
+    tr.transform(self.mVertices[3], src.w, 0);
+
+    if (!(mFlags & DisplayHardware::SLOW_CONFIG)) {
+        // Too slow to do this in software
+        self.mDrawingState.flags |= ISurfaceComposer::eLayerFilter;
+    }
+
+    if (UNLIKELY(mTextureName == -1LU)) {
+        mTextureName = createTexture();
+        GLuint w=0, h=0;
+        const Region dirty(Rect(t.width, t.height));
+        loadTexture(dirty, mTextureName, t, w, h);
+    }
+    self.mDrawingState.alpha = 255; //-int(alpha*255);
+    const Region clip(Rect( srect.l, srect.t, srect.r, srect.b ));
+    drawWithOpenGL(clip, mTextureName, t);
+    
+    if (alpha > 0) {
+        const float sign = (!targetOrientation) ? 1.0f : -1.0f;
+        tr.set(f + sign*(M_PI * 0.5f * ROTATION_FACTOR), w*0.5f, h*0.5f);
+        tr.scale(s, w*0.5f, h*0.5f);
+        tr.transform(self.mVertices[0], 0, 0);
+        tr.transform(self.mVertices[1], 0, src.h);
+        tr.transform(self.mVertices[2], src.w, src.h);
+        tr.transform(self.mVertices[3], src.w, 0);
+
+        copybit_image_t src;
+        mBitmapIn.getBitmapSurface(&src);
+        t.data = (GGLubyte*)(intptr_t(src.base) + src.offset);
+        if (UNLIKELY(mTextureNameIn == -1LU)) {
+            mTextureNameIn = createTexture();
+            GLuint w=0, h=0;
+            const Region dirty(Rect(t.width, t.height));
+            loadTexture(dirty, mTextureNameIn, t, w, h);
+        }
+        self.mDrawingState.alpha = int(alpha*255);
+        const Region clip(Rect( srect.l, srect.t, srect.r, srect.b ));
+        drawWithOpenGL(clip, mTextureNameIn, t);
+    }
+}
+
+// ---------------------------------------------------------------------------
+
+}; // namespace android
diff --git a/libs/surfaceflinger/LayerOrientationAnimRotate.h b/libs/surfaceflinger/LayerOrientationAnimRotate.h
new file mode 100644
index 0000000..5ca5780
--- /dev/null
+++ b/libs/surfaceflinger/LayerOrientationAnimRotate.h
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_LAYER_ORIENTATION_ANIM_ROTATE_H
+#define ANDROID_LAYER_ORIENTATION_ANIM_ROTATE_H
+
+#include <stdint.h>
+#include <sys/types.h>
+#include <utils/threads.h>
+#include <utils/Parcel.h>
+
+#include "LayerBase.h"
+#include "LayerBitmap.h"
+
+namespace android {
+
+// ---------------------------------------------------------------------------
+class OrientationAnimation;
+
+class LayerOrientationAnimRotate : public LayerOrientationAnimBase
+{
+public:    
+    static const uint32_t typeInfo;
+    static const char* const typeID;
+    virtual char const* getTypeID() const { return typeID; }
+    virtual uint32_t getTypeInfo() const { return typeInfo; }
+    
+    LayerOrientationAnimRotate(SurfaceFlinger* flinger, DisplayID display,
+                        OrientationAnimation* anim, 
+                        const LayerBitmap& zoomOut,
+                        const LayerBitmap& zoomIn);
+        virtual ~LayerOrientationAnimRotate();
+
+            void onOrientationCompleted();
+
+    virtual void onDraw(const Region& clip) const;
+    virtual Point getPhysicalSize() const;
+    virtual void validateVisibility(const Transform& globalTransform);
+    virtual bool needsBlending() const;
+    virtual bool isSecure() const       { return false; }
+private:
+    void drawScaled(float angle, float scale, float alpha) const;
+    
+    OrientationAnimation* mAnim;
+    LayerBitmap mBitmap;
+    LayerBitmap mBitmapIn;
+    nsecs_t mStartTime;
+    nsecs_t mFinishTime;
+    bool mOrientationCompleted;
+    mutable bool mFirstRedraw;
+    mutable float mLastNormalizedTime;
+    mutable float mLastAngle;
+    mutable float mLastScale;
+    mutable GLuint  mTextureName;
+    mutable GLuint  mTextureNameIn;
+    mutable bool mNeedsBlending;
+};
+
+// ---------------------------------------------------------------------------
+
+}; // namespace android
+
+#endif // ANDROID_LAYER_ORIENTATION_ANIM_ROTATE_H
diff --git a/libs/surfaceflinger/OrientationAnimation.cpp b/libs/surfaceflinger/OrientationAnimation.cpp
index f6f1326..e59688e 100644
--- a/libs/surfaceflinger/OrientationAnimation.cpp
+++ b/libs/surfaceflinger/OrientationAnimation.cpp
@@ -21,6 +21,7 @@
 #include <limits.h>
 
 #include "LayerOrientationAnim.h"
+#include "LayerOrientationAnimRotate.h"
 #include "OrientationAnimation.h"
 #include "SurfaceFlinger.h"
 #include "VRamHeap.h"
@@ -112,8 +113,14 @@
     bitmap.getBitmapSurface(&front);
     hw.copyFrontToImage(front);
 
-    LayerOrientationAnim* l = new LayerOrientationAnim(
+    LayerOrientationAnimBase* l;
+    
+    l = new LayerOrientationAnim(
             mFlinger.get(), 0, this, bitmap, bitmapIn);
+
+    //l = new LayerOrientationAnimRotate(
+    //        mFlinger.get(), 0, this, bitmap, bitmapIn);
+
     l->initStates(w, h, 0);
     l->setLayer(INT_MAX-1);
     mFlinger->addLayer(l);
diff --git a/libs/surfaceflinger/OrientationAnimation.h b/libs/surfaceflinger/OrientationAnimation.h
index ba33fce..b170dcb 100644
--- a/libs/surfaceflinger/OrientationAnimation.h
+++ b/libs/surfaceflinger/OrientationAnimation.h
@@ -62,7 +62,7 @@
 
     sp<SurfaceFlinger> mFlinger;
     sp<MemoryDealer> mTemporaryDealer;
-    LayerOrientationAnim* mLayerOrientationAnim;
+    LayerOrientationAnimBase* mLayerOrientationAnim;
     int mState;
 };
 
diff --git a/libs/surfaceflinger/SurfaceFlinger.cpp b/libs/surfaceflinger/SurfaceFlinger.cpp
index d915a84..8499b67 100644
--- a/libs/surfaceflinger/SurfaceFlinger.cpp
+++ b/libs/surfaceflinger/SurfaceFlinger.cpp
@@ -1804,6 +1804,7 @@
     if (orientation == ISurfaceComposer::eOrientationDefault) {
         // make sure the default orientation is optimal
         mOrientationTransform.reset();
+        mOrientation = orientation;
         mGlobalTransform = mTransform;
         return NO_ERROR;
     }
@@ -1824,7 +1825,7 @@
         GraphicPlane::orientationToTransfrom(orientation, w, h,
                 &mOrientationTransform);
     }
-    
+    mOrientation = orientation;
     mGlobalTransform = mOrientationTransform * mTransform;
     return NO_ERROR;
 }
diff --git a/libs/surfaceflinger/SurfaceFlinger.h b/libs/surfaceflinger/SurfaceFlinger.h
index f7d7764..3c10481 100644
--- a/libs/surfaceflinger/SurfaceFlinger.h
+++ b/libs/surfaceflinger/SurfaceFlinger.h
@@ -122,6 +122,7 @@
         void                    setDisplayHardware(DisplayHardware *);
         void                    setTransform(const Transform& tr);
         status_t                setOrientation(int orientation);
+        int                     getOrientation() const { return mOrientation; }
 
         const DisplayHardware&  displayHardware() const;
         const Transform&        transform() const;
@@ -133,6 +134,7 @@
         Transform               mTransform;
         Transform               mOrientationTransform;
         Transform               mGlobalTransform;
+        int                     mOrientation;
 };
 
 // ---------------------------------------------------------------------------
diff --git a/libs/surfaceflinger/Transform.cpp b/libs/surfaceflinger/Transform.cpp
index bec7a64..e8b0f45 100644
--- a/libs/surfaceflinger/Transform.cpp
+++ b/libs/surfaceflinger/Transform.cpp
@@ -103,6 +103,25 @@
     mType |= 0x80000000;
 }
 
+void Transform::set(float radian, float x, float y)
+{
+    float r00 = cosf(radian);    float r01 = -sinf(radian);
+    float r10 = sinf(radian);    float r11 =  cosf(radian);
+    mTransform.set(SkMatrix::kMScaleX, SkFloatToScalar(r00));
+    mTransform.set(SkMatrix::kMSkewX, SkFloatToScalar(r01));
+    mTransform.set(SkMatrix::kMSkewY, SkFloatToScalar(r10));
+    mTransform.set(SkMatrix::kMScaleY, SkFloatToScalar(r11));
+    mTransform.set(SkMatrix::kMTransX, SkIntToScalar(x - r00*x - r01*y));
+    mTransform.set(SkMatrix::kMTransY, SkIntToScalar(y - r10*x - r11*y));
+    mType |= 0x80000000 | SkMatrix::kTranslate_Mask;
+}
+
+void Transform::scale(float s, float x, float y)
+{
+    mTransform.postScale(s, s, x, y); 
+    mType |= 0x80000000;
+}
+
 void Transform::set(int tx, int ty)
 {
     if (tx | ty) {
diff --git a/libs/surfaceflinger/Transform.h b/libs/surfaceflinger/Transform.h
index 0b4835e..4c4528e 100644
--- a/libs/surfaceflinger/Transform.h
+++ b/libs/surfaceflinger/Transform.h
@@ -60,7 +60,9 @@
             void    reset();
             void    set(float xx, float xy, float yx, float yy);
             void    set(int tx, int ty);
-
+            void    set(float radian, float x, float y);
+            void    scale(float s, float x, float y);
+            
             Rect    makeBounds(int w, int h) const;
             void    transform(GLfixed* point, int x, int y) const;
             Region  transform(const Region& reg) const;